fltk_form/
lib.rs

1/*!
2    # fltk-form
3
4    This crate aims to simplify generating gui from a data structure.
5
6    ## Usage
7    ```toml,no_run
8    [dependencies]
9    fltk = "1.2.16"
10    fltk-form = "0.1"
11    fltk-form-derive = "0.1"
12    ```
13
14    ## Example
15    ```rust,no_run
16    #[macro_use]
17    extern crate fltk_form_derive;
18
19    use fltk::{prelude::*, *};
20    use fltk_form::{FltkForm, HasProps, FlImage};
21
22    #[derive(Copy, Debug, Clone, FltkForm)]
23    pub enum MyEnum {
24        A,
25        B,
26        C,
27    }
28
29    #[derive(Debug, Clone, FltkForm)]
30    pub struct MyStruct {
31        a: f64,
32        b: f64,
33        c: String,
34        d: MyEnum,
35        e: bool,
36        f:FlImage,
37    }
38
39    impl MyStruct {
40        pub fn default() -> Self {
41            Self {
42                a: 0.0,
43                b: 3.0,
44                c: String::new(),
45                d: MyEnum::A,
46                e: true,
47                f:FlImage(String::from("examples/orange_circle.svg")),
48            }
49        }
50    }
51
52    fn main() {
53        let my_struct = MyStruct::default();
54
55        let a = app::App::default().with_scheme(app::Scheme::Gtk);
56        app::set_background_color(222, 222, 222);
57
58        let mut win = window::Window::default().with_size(400, 300);
59        let mut grp = group::Scroll::default()
60            .with_size(300, 200)
61            .center_of_parent();
62        let form = my_struct.generate();
63        grp.end();
64        let mut btn = button::Button::default()
65            .with_label("print")
66            .with_size(80, 30)
67            .below_of(&grp, 5)
68            .center_x(&grp);
69        grp.set_frame(enums::FrameType::EngravedFrame);
70        win.end();
71        win.show();
72
73        let v = form.get_prop("b");
74        assert_eq!(v, Some("3.0".to_owned()));
75
76        btn.set_callback(move |_| {
77            println!("{:?}", form.get_props());
78        });
79
80        while a.wait() {
81            win.redraw();
82        }
83    }
84    ```
85
86
87    You can also rename properties using the rename_prop() method:
88    ```rust,no_run
89    #[macro_use]
90    extern crate fltk_form_derive;
91
92    use fltk::{prelude::*, *};
93    use fltk_form::{FltkForm, HasProps};
94
95    #[derive(Copy, Debug, Clone, FltkForm)]
96    pub enum MyEnum {
97        A,
98        B,
99        C,
100    }
101
102    #[allow(non_snake_case)]
103    #[derive(Debug, Clone, FltkForm)]
104    pub struct MyStruct {
105        very_long_name: f64,
106        second_value: f64,
107        full_name: String,
108        Choices: MyEnum,
109        do_it: bool,
110    }
111
112    impl MyStruct {
113        pub fn default() -> Self {
114            Self {
115                very_long_name: 0.0,
116                second_value: 3.0,
117                full_name: String::new(),
118                Choices: MyEnum::A,
119                do_it: true,
120            }
121        }
122    }
123
124    fn main() {
125        let my_struct = MyStruct::default();
126
127        let a = app::App::default().with_scheme(app::Scheme::Gtk);
128        app::set_background_color(222, 222, 222);
129
130        let mut win = window::Window::default().with_size(400, 300);
131        let mut grp = group::Group::default()
132            .with_size(300, 200)
133            .center_of_parent()
134            .with_label("Form 1")
135            .with_align(enums::Align::Top | enums::Align::Left);
136
137        let mut form = my_struct.generate();
138        form.set_label("");
139        form.rename_prop("very_long_name", "First Value");
140        form.rename_prop("second_value", "Second Value");
141        form.rename_prop("full_name", "Full name");
142        form.rename_prop("do_it", "Do it?");
143
144        grp.end();
145        grp.set_frame(enums::FrameType::EngravedFrame);
146        let mut btn = button::Button::default()
147            .with_label("print")
148            .with_size(80, 30)
149            .below_of(&grp, 5)
150            .center_x(&grp);
151        win.end();
152        win.show();
153
154        let v = form.get_prop("First Value");
155        assert_eq!(v, Some("0.0".to_owned()));
156
157        btn.set_callback(move |_| {
158            println!("{:?}", form.get_props());
159        });
160
161        a.run().unwrap();
162    }
163    ```
164*/
165
166use fltk::{image::*, prelude::*, utils::is_ptr_of, *};
167use std::collections::HashMap;
168use std::fmt;
169use std::path::Path;
170
171pub mod utils;
172
173pub fn make_image_frame<P: AsRef<Path>>(filename: P) -> frame::Frame {
174    let mut frame = frame::Frame::default();
175    let img = SharedImage::load(&filename).ok();
176    if let Some(ref img) = img {
177        let w = img.width();
178        let h = img.height();
179        frame.set_size(w, h);
180    }
181    frame.set_image(img);
182    frame.set_tooltip(filename.as_ref().to_str().unwrap());
183    frame
184}
185
186#[derive(Debug, Clone)]
187pub struct FlImage(pub String);
188
189impl fmt::Display for FlImage {
190    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191        write!(f, "{}", self.0)
192    }
193}
194#[derive(Debug)]
195#[non_exhaustive]
196pub enum FltkFormError {
197    FltkError(FltkErrorKind),
198    Internal(FltkFormErrorKind),
199    Unknown(String),
200}
201
202unsafe impl Send for FltkFormError {}
203unsafe impl Sync for FltkFormError {}
204
205#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
206pub enum FltkFormErrorKind {
207    PropertyInexistent,
208    FailedToChangeData,
209}
210
211impl std::error::Error for FltkFormError {
212    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
213        None
214    }
215}
216
217impl fmt::Display for FltkFormError {
218    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
219        match *self {
220            FltkFormError::Internal(ref err) => write!(f, "An internal error occured {:?}", err),
221            FltkFormError::Unknown(ref err) => write!(f, "An unknown error occurred {:?}", err),
222            FltkFormError::FltkError(ref err) => write!(f, "an fltk error occured {:?}", err),
223        }
224    }
225}
226
227#[derive(Clone, Debug)]
228pub struct Form {
229    grp: group::Group,
230}
231
232impl Default for Form {
233    fn default() -> Self {
234        Form::new(0, 0, 0, 0, None)
235    }
236}
237
238impl Form {
239    pub fn new<S: Into<Option<&'static str>>>(x: i32, y: i32, w: i32, h: i32, label: S) -> Self {
240        let grp = group::Group::new(x, y, w, h, label);
241        grp.end();
242        Self { grp }
243    }
244
245    pub fn default_fill() -> Self {
246        Form::default().size_of_parent().center_of_parent()
247    }
248
249    pub fn set_data<T: FltkForm>(&mut self, data: T) {
250        self.begin();
251        let mut w = data.generate();
252        w.resize(self.x(), self.y(), self.w(), self.h());
253        self.end();
254    }
255
256    pub fn from_data<T: FltkForm>(mut self, data: T) -> Self {
257        self.set_data(data);
258        self
259    }
260
261    pub fn set_data_view<T: FltkForm>(&mut self, data: T) {
262        self.begin();
263        let mut w = data.view();
264        w.resize(self.x(), self.y(), self.w(), self.h());
265        self.end();
266    }
267
268    pub fn from_data_view<T: FltkForm>(mut self, data: T) -> Self {
269        self.set_data_view(data);
270        self
271    }
272
273    pub fn get_prop(&self, prop: &str) -> Option<String> {
274        if let Some(child) = self.grp.child(0) {
275            if let Some(grp) = child.as_group() {
276                for child in grp.into_iter() {
277                    if child.label() == prop {
278                        let ptr = child.as_widget_ptr();
279                        let val = if is_ptr_of::<input::Input>(ptr) {
280                            1
281                        } else if is_ptr_of::<button::CheckButton>(ptr) {
282                            2
283                        } else if is_ptr_of::<menu::Choice>(ptr) {
284                            3
285                        } else {
286                            4
287                        };
288                        match val {
289                            1 => {
290                                let inp = input::Input::from_dyn_widget_ptr(ptr as _).unwrap();
291                                return Some(inp.value());
292                            }
293                            2 => {
294                                let inp =
295                                    button::CheckButton::from_dyn_widget_ptr(ptr as _).unwrap();
296                                return Some(inp.value().to_string());
297                            }
298                            3 => {
299                                let choice = menu::Choice::from_dyn_widget_ptr(ptr as _).unwrap();
300                                return choice.choice();
301                            }
302                            _ => {
303                                let wid = widget::Widget::from_dyn_widget_ptr(ptr as _).unwrap();
304                                return Some(wid.label());
305                            }
306                        }
307                    }
308                }
309                None
310            } else {
311                None
312            }
313        } else {
314            None
315        }
316    }
317
318    pub fn set_prop(&mut self, prop: &str, value: &str) -> Result<(), FltkFormError> {
319        let mut found = false;
320        if let Some(child) = self.grp.child(0) {
321            if let Some(grp) = child.as_group() {
322                for child in grp.into_iter() {
323                    if child.label() == prop {
324                        found = true;
325                        let ptr = child.as_widget_ptr();
326                        let val = if is_ptr_of::<input::Input>(ptr) {
327                            1
328                        } else if is_ptr_of::<button::CheckButton>(ptr) {
329                            2
330                        } else if is_ptr_of::<menu::Choice>(ptr) {
331                            3
332                        } else {
333                            4
334                        };
335                        match val {
336                            1 => {
337                                let mut inp =
338                                    input::Input::from_dyn_widget_ptr(ptr as _).unwrap();
339                                inp.set_value(value);
340                            }
341                            2 => {
342                                let mut inp =
343                                    button::CheckButton::from_dyn_widget_ptr(ptr as _).unwrap();
344                                let v = value == "true";
345                                inp.set_value(v);
346                            }
347                            3 => {
348                                let mut choice =
349                                    menu::Choice::from_dyn_widget_ptr(ptr as _).unwrap();
350                                let idx = choice.find_index(value);
351                                choice.set_value(idx);
352                            }
353                            _ => (),
354                        }
355                    }
356                }
357            }
358        }
359        if !found {
360            return Err(FltkFormError::Internal(
361                FltkFormErrorKind::PropertyInexistent,
362            ));
363        }
364        Ok(())
365    }
366
367    pub fn get_props(&self) -> HashMap<String, String> {
368        let mut temp = HashMap::new();
369        if let Some(c) = self.grp.child(0) {
370            if let Some(grp) = c.as_group() {
371                for child in grp.into_iter() {
372                    if !child.label().is_empty() {
373                        if let Some(prop) = self.get_prop(&child.label()) {
374                            temp.insert(child.label().clone(), prop);
375                        }
376                    }
377                }
378            }
379        }
380        temp
381    }
382
383    pub fn rename_prop(&self, prop: &str, new_name: &str) {
384        if let Some(child) = self.grp.child(0) {
385            if let Some(grp) = child.as_group() {
386                for mut child in grp.into_iter() {
387                    if child.label() == prop {
388                        child.set_label(new_name);
389                    }
390                }
391            }
392        }
393    }
394
395    pub fn get_widget(&self, prop: &str) -> Option<Box<dyn WidgetExt>> {
396        if let Some(grp) = self.as_group() {
397            for child in grp.into_iter() {
398                if child.label() == prop {
399                    return Some(Box::new(child));
400                }
401            }
402            None
403        } else if self.label() == prop {
404            let wid: widget::Widget = widget::Widget::from_dyn_widget_ptr(self.as_widget_ptr()).unwrap();
405            Some(Box::new(wid))
406        } else {
407            None
408        }
409    }
410}
411
412fltk::widget_extends!(Form, group::Group, grp);
413
414pub trait FltkForm {
415    fn generate(&self) -> Box<dyn WidgetExt>;
416    fn view(&self) -> Box<dyn WidgetExt>;
417}
418
419impl FltkForm for FlImage {
420    fn generate(&self) -> Box<dyn WidgetExt> {
421        let val = format!("{}", *self);
422        let i = make_image_frame(val.as_str());
423        Box::new(i)
424    }
425    fn view(&self) -> Box<dyn WidgetExt> {
426        let val = format!("{}", *self);
427        let i = make_image_frame(val.as_str());
428        Box::new(i)
429    }
430}
431
432impl FltkForm for f64 {
433    fn generate(&self) -> Box<dyn WidgetExt> {
434        let mut i = input::FloatInput::default();
435        let val = format!("{:?}", *self);
436        i.set_value(&val);
437        Box::new(i)
438    }
439    fn view(&self) -> Box<dyn WidgetExt> {
440        let mut i = output::Output::default();
441        let val = format!("{:?}", *self);
442        i.set_value(&val);
443        Box::new(i)
444    }
445}
446
447impl FltkForm for f32 {
448    fn generate(&self) -> Box<dyn WidgetExt> {
449        let mut i = input::FloatInput::default();
450        let val = format!("{:?}", *self);
451        i.set_value(&val);
452        Box::new(i)
453    }
454    fn view(&self) -> Box<dyn WidgetExt> {
455        let mut i = output::Output::default();
456        let val = format!("{:?}", *self);
457        i.set_value(&val);
458        Box::new(i)
459    }
460}
461
462impl FltkForm for i32 {
463    fn generate(&self) -> Box<dyn WidgetExt> {
464        let mut i = input::IntInput::default();
465        let val = format!("{:?}", *self);
466        i.set_value(&val);
467        Box::new(i)
468    }
469    fn view(&self) -> Box<dyn WidgetExt> {
470        let mut i = output::Output::default();
471        let val = format!("{:?}", *self);
472        i.set_value(&val);
473        Box::new(i)
474    }
475}
476
477impl FltkForm for u32 {
478    fn generate(&self) -> Box<dyn WidgetExt> {
479        let mut i = input::IntInput::default();
480        let val = format!("{:?}", *self);
481        i.set_value(&val);
482        Box::new(i)
483    }
484    fn view(&self) -> Box<dyn WidgetExt> {
485        let mut i = output::Output::default();
486        let val = format!("{:?}", *self);
487        i.set_value(&val);
488        Box::new(i)
489    }
490}
491
492impl FltkForm for i64 {
493    fn generate(&self) -> Box<dyn WidgetExt> {
494        let mut i = input::IntInput::default();
495        let val = format!("{:?}", *self);
496        i.set_value(&val);
497        Box::new(i)
498    }
499    fn view(&self) -> Box<dyn WidgetExt> {
500        let mut i = output::Output::default();
501        let val = format!("{:?}", *self);
502        i.set_value(&val);
503        Box::new(i)
504    }
505}
506
507impl FltkForm for u64 {
508    fn generate(&self) -> Box<dyn WidgetExt> {
509        let mut i = input::IntInput::default();
510        let val = format!("{:?}", *self);
511        i.set_value(&val);
512        Box::new(i)
513    }
514    fn view(&self) -> Box<dyn WidgetExt> {
515        let mut i = output::Output::default();
516        let val = format!("{:?}", *self);
517        i.set_value(&val);
518        Box::new(i)
519    }
520}
521
522impl FltkForm for isize {
523    fn generate(&self) -> Box<dyn WidgetExt> {
524        let mut i = input::IntInput::default();
525        let val = format!("{:?}", *self);
526        i.set_value(&val);
527        Box::new(i)
528    }
529    fn view(&self) -> Box<dyn WidgetExt> {
530        let mut i = output::Output::default();
531        let val = format!("{:?}", *self);
532        i.set_value(&val);
533        Box::new(i)
534    }
535}
536
537impl FltkForm for usize {
538    fn generate(&self) -> Box<dyn WidgetExt> {
539        let mut i = input::IntInput::default();
540        let val = format!("{:?}", *self);
541        i.set_value(&val);
542        Box::new(i)
543    }
544    fn view(&self) -> Box<dyn WidgetExt> {
545        let mut i = output::Output::default();
546        let val = format!("{:?}", *self);
547        i.set_value(&val);
548        Box::new(i)
549    }
550}
551
552impl FltkForm for i8 {
553    fn generate(&self) -> Box<dyn WidgetExt> {
554        let mut i = input::IntInput::default();
555        let val = format!("{:?}", *self);
556        i.set_value(&val);
557        Box::new(i)
558    }
559    fn view(&self) -> Box<dyn WidgetExt> {
560        let mut i = output::Output::default();
561        let val = format!("{:?}", *self);
562        i.set_value(&val);
563        Box::new(i)
564    }
565}
566
567impl FltkForm for u8 {
568    fn generate(&self) -> Box<dyn WidgetExt> {
569        let mut i = input::IntInput::default();
570        let val = format!("{:?}", *self);
571        i.set_value(&val);
572        Box::new(i)
573    }
574    fn view(&self) -> Box<dyn WidgetExt> {
575        let mut i = output::Output::default();
576        let val = format!("{:?}", *self);
577        i.set_value(&val);
578        Box::new(i)
579    }
580}
581
582impl FltkForm for i16 {
583    fn generate(&self) -> Box<dyn WidgetExt> {
584        let mut i = input::IntInput::default();
585        let val = format!("{:?}", *self);
586        i.set_value(&val);
587        Box::new(i)
588    }
589    fn view(&self) -> Box<dyn WidgetExt> {
590        let mut i = output::Output::default();
591        let val = format!("{:?}", *self);
592        i.set_value(&val);
593        Box::new(i)
594    }
595}
596
597impl FltkForm for u16 {
598    fn generate(&self) -> Box<dyn WidgetExt> {
599        let mut i = input::IntInput::default();
600        let val = format!("{:?}", *self);
601        i.set_value(&val);
602        Box::new(i)
603    }
604    fn view(&self) -> Box<dyn WidgetExt> {
605        let mut i = output::Output::default();
606        let val = format!("{:?}", *self);
607        i.set_value(&val);
608        Box::new(i)
609    }
610}
611
612impl FltkForm for String {
613    fn generate(&self) -> Box<dyn WidgetExt> {
614        let mut i = input::Input::default();
615        i.set_value(self);
616        Box::new(i)
617    }
618    fn view(&self) -> Box<dyn WidgetExt> {
619        let mut i = output::Output::default();
620        i.set_value(self);
621        Box::new(i)
622    }
623}
624
625impl FltkForm for &str {
626    fn generate(&self) -> Box<dyn WidgetExt> {
627        let i = frame::Frame::default().with_label(self);
628        Box::new(i)
629    }
630    fn view(&self) -> Box<dyn WidgetExt> {
631        let i = frame::Frame::default().with_label(self);
632        Box::new(i)
633    }
634}
635
636impl FltkForm for bool {
637    fn generate(&self) -> Box<dyn WidgetExt> {
638        let mut i = button::CheckButton::default().with_align(enums::Align::Left);
639        i.set_value(*self);
640        i.clear_visible_focus();
641        Box::new(i)
642    }
643    fn view(&self) -> Box<dyn WidgetExt> {
644        let mut i = output::Output::default().with_align(enums::Align::Left);
645        i.set_value(&format!("{}", *self));
646        i.clear_visible_focus();
647        Box::new(i)
648    }
649}
650
651impl<T> FltkForm for Vec<T>
652where
653    T: FltkForm,
654{
655    fn generate(&self) -> Box<dyn WidgetExt> {
656        let mut g = group::Pack::default();
657        g.set_spacing(5);
658        for v in self.iter() {
659            let mut w = v.generate();
660            w.set_align(enums::Align::Left);
661            w.set_size(w.w(), 30);
662        }
663        g.end();
664        Box::new(g)
665    }
666    fn view(&self) -> Box<dyn WidgetExt> {
667        let mut g = group::Pack::default();
668        g.set_spacing(5);
669        for v in self.iter() {
670            let mut w = v.view();
671            w.set_align(enums::Align::Left);
672            w.set_size(w.w(), 30);
673        }
674        g.end();
675        Box::new(g)
676    }
677}
678
679#[allow(clippy::borrowed_box)]
680fn rename_prop_(wid: &Box<dyn WidgetExt>, prop: &str, new_name: &str) {
681    if let Some(grp) = wid.as_group() {
682        for mut child in grp.into_iter() {
683            if child.label() == prop {
684                child.set_label(new_name);
685            }
686        }
687    }
688}
689
690#[allow(clippy::borrowed_box)]
691fn get_prop_(wid: &Box<dyn WidgetExt>, prop: &str) -> Option<String> {
692    if let Some(grp) = wid.as_group() {
693        for child in grp.into_iter() {
694            if child.label() == prop {
695                let ptr = child.as_widget_ptr();
696                let val = if is_ptr_of::<input::Input>(ptr) {
697                    1
698                } else if is_ptr_of::<button::CheckButton>(ptr) {
699                    2
700                } else if is_ptr_of::<menu::Choice>(ptr) {
701                    3
702                } else {
703                    4
704                };
705                match val {
706                    1 => {
707                        let inp = input::Input::from_dyn_widget_ptr(ptr as _).unwrap();
708                        return Some(inp.value());
709                    }
710                    2 => {
711                        let inp = button::CheckButton::from_dyn_widget_ptr(ptr as _).unwrap();
712                        return Some(format!("{}", inp.value()));
713                    }
714                    3 => {
715                        let choice = menu::Choice::from_dyn_widget_ptr(ptr as _).unwrap();
716                        return choice.choice();
717                    }
718                    _ => {
719                        let wid = widget::Widget::from_dyn_widget_ptr(ptr as _).unwrap();
720                        return Some(wid.label());
721                    }
722                }
723            }
724        }
725        None
726    } else {
727        None
728    }
729}
730
731#[allow(clippy::borrowed_box)]
732fn set_prop_(wid: &Box<dyn WidgetExt>, prop: &str, value: &str) -> Result<(), FltkFormError> {
733    let mut found = false;
734    if let Some(grp) = wid.as_group() {
735        for child in grp.into_iter() {
736            if child.label() == prop {
737                found = true;
738                let ptr = child.as_widget_ptr();
739                let val = if is_ptr_of::<input::Input>(ptr) {
740                    1
741                } else if is_ptr_of::<button::CheckButton>(ptr) {
742                    2
743                } else if is_ptr_of::<menu::Choice>(ptr) {
744                    3
745                } else {
746                    4
747                };
748                match val {
749                    1 => {
750                        let mut inp = input::Input::from_dyn_widget_ptr(ptr as _).unwrap();
751                        inp.set_value(value);
752                    }
753                    2 => {
754                        let mut inp = button::CheckButton::from_dyn_widget_ptr(ptr as _).unwrap();
755                        let v = value == "true";
756                        inp.set_value(v);
757                    }
758                    3 => {
759                        let mut choice = menu::Choice::from_dyn_widget_ptr(ptr as _).unwrap();
760                        let idx = choice.find_index(value);
761                        choice.set_value(idx);
762                    }
763                    _ => (),
764                }
765            }
766        }
767    }
768    if !found {
769        return Err(FltkFormError::Internal(
770            FltkFormErrorKind::PropertyInexistent,
771        ));
772    }
773    Ok(())
774}
775
776#[allow(clippy::borrowed_box)]
777fn get_props_(wid: &Box<dyn WidgetExt>) -> HashMap<String, String> {
778    let mut temp = HashMap::new();
779    if let Some(grp) = wid.as_group() {
780        for child in grp.into_iter() {
781            if !child.label().is_empty() {
782                if let Some(prop) = get_prop_(wid, &child.label()) {
783                    temp.insert(child.label().clone(), prop);
784                }
785            }
786        }
787    }
788    temp
789}
790
791#[allow(clippy::borrowed_box)]
792fn get_widget_(wid: &Box<dyn WidgetExt>, prop: &str) -> Option<Box<dyn WidgetExt>> {
793    if let Some(grp) = wid.as_group() {
794        for child in grp.into_iter() {
795            if child.label() == prop {
796                return Some(Box::new(child));
797            }
798        }
799        None
800    } else if wid.label() == prop {
801        let wid: widget::Widget = widget::Widget::from_dyn_widget_ptr(wid.as_widget_ptr()).unwrap();
802        Some(Box::new(wid))
803    } else {
804        None
805    }
806}
807
808pub trait HasProps {
809    fn get_prop(&self, prop: &str) -> Option<String>;
810    fn set_prop(&mut self, prop: &str, value: &str) -> Result<(), FltkFormError>;
811    fn get_props(&self) -> HashMap<String, String>;
812    fn rename_prop(&mut self, prop: &str, new_name: &str);
813    fn get_widget(&self, prop: &str) -> Option<Box<dyn WidgetExt>>;
814}
815
816impl HasProps for Box<dyn WidgetExt> {
817    fn get_prop(&self, prop: &str) -> Option<String> {
818        get_prop_(self, prop)
819    }
820    fn set_prop(&mut self, prop: &str, value: &str) -> Result<(), FltkFormError> {
821        set_prop_(self, prop, value)
822    }
823    fn get_props(&self) -> HashMap<String, String> {
824        get_props_(self)
825    }
826    fn rename_prop(&mut self, prop: &str, new_name: &str) {
827        rename_prop_(self, prop, new_name);
828    }
829    fn get_widget(&self, prop: &str) -> Option<Box<dyn WidgetExt>> {
830        get_widget_(self, prop)
831    }
832}