New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
typed Generics possible? #2
Comments
It should be implementable I think, never done it before though. But currently it won't work. |
😮 That would be cool if it was possible. Is there a way the end user can easily create their own? Could one just make an Part of my goal as you probably can tell is to remake the "character-maker" program and make it work with Oh, I just thought of another use case: Thanks for being into making this, I find this possibility so fascinating and almost endless! When it is all done you can say character-maker uses this 😺 as the way to generate the interface. And eventually Rust Hero as well. |
You, you could just impl FltkForm for any type of your choosing, then return a Box::new(some_widget). let form = my_struct.view(); or using the form widget: let form = Form::default().from_data_view(my_struct); That means, if you would like, you'd have to implement both methods of FltkForm (generate and view). |
Ok here is where I am getting stuck:
Basically how do I do |
BTW I had to make a |
There are no such derives or bounds in the standard library. There is a crate called num which provides such bounds and numeric traits. |
|
Vecs (and other collections) implement the Iterator trait, so it might be used as a trait bound. Not sure how that would compose since Rust currently doesn’t have generic specialization. |
I have been on the Rust chat channel and cannot come up with a good solution for this. As far as I can tell it is not fully possible to do what I want, as Vectors continue to interfere with numbers trait bounds. The workaround that "works" (read: compiles) is this: pub trait Primitive {}
macro_rules! primitive {
($($type:ty),*) => {
$(impl Primitive for $type {})*
}
}
primitive!(i8, u8, i16, u16, i32, f32, i64, f64, isize, usize);
//...
impl<T:Copy
+ Primitive
+ Default
+ Debug // could use Display {} instead
+ num::NumCast> FltkForm for T {
fn generate(&self) -> Box<dyn WidgetExt> {
let mut i = input::FloatInput::default();
let val = format!("{:?}", *self);
i.set_value(&val);
unsafe {
i.set_raw_user_data(transmute(1_usize));
}
Box::new(i)
}
fn view(&self) -> Box<dyn WidgetExt> {
let mut i = output::Output::default();
let val = format!("{:?}", *self);
i.set_value(&val);
unsafe {
i.set_raw_user_data(transmute(1_usize));
}
Box::new(i)
}
}
//... But it still fails with vectors when using with rpgstat:
The doc test for I may have to give up on this idea.... |
@MoAlyousef I am trying to fn generate(&self) -> Box<dyn WidgetExt> {
let mut g = group::Pack::default();
g.set_spacing(5);
//repeat numerous times for "things"
let mut thing = self.thing.generate();
thing.set_align(enums::Align::Left);
thing.set_size(w.w(), 30);
g.end();
Box::new(g)
} Using: fn main () {
use std::fs;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
let app = app::App::default().with_scheme(app::Scheme::Gtk);
app::set_background_color(222, 222, 222);
let mut win = window::Window::default().with_size(400, 300);
// substitute Things for real struct name
let my_struct = Things::<f64>::default();
let mut grp = group::Scroll::default()
.with_size(300, 200)
.center_of_parent();
// inside group
let form = my_struct.generate();
grp.end();
let mut btn = button::Button::default()
.with_label("print")
.with_size(80, 30)
.below_of(&grp, 5)
.center_x(&grp);
win.end();
win.show();
while app.wait() {
win.redraw();
}
} But this does not function properly as it does with manual items. What am I missing to close this issue? |
The macro expands in cases of structs roughly like this: #[derive(Debug, Clone)]
pub struct MyStruct<T> {
a: T,
b: f64,
c: String,
}
impl<T: Copy + Default + FltkForm> MyStruct<T> {
pub fn default() -> Self {
Self {
a: T::default(),
b: 3.0,
c: String::new(),
}
}
}
impl<T: Copy + Default + FltkForm> FltkForm for MyStruct<T> {
fn generate(&self) -> Box<dyn WidgetExt> {
let mut p = group::Pack::default()
.with_label(&format!("{}", "MyStruct"))
.with_align(fltk::enums::Align::Left | fltk::enums::Align::Top);
p.set_spacing(5);
let mut i = self.a.generate();
if unsafe { !i.raw_user_data().is_null() } {
i.set_align(fltk::enums::Align::Left);
i.set_label("a");
}
let mut i = self.b.generate();
if unsafe { !i.raw_user_data().is_null() } {
i.set_align(fltk::enums::Align::Left);
i.set_label("b");
}
let mut i = self.c.generate();
if unsafe { !i.raw_user_data().is_null() } {
i.set_align(fltk::enums::Align::Left);
i.set_label("c");
}
p.end();
let parent = p.parent().unwrap();
p.resize(
parent.x() + (parent.width()/2), parent.y() + parent.h() / 9, parent.width() / 3, (3 * 30 + 5 * 3) as i32
);
p.auto_layout();
Box::new(p)
}
fn view(&self) -> Box<dyn WidgetExt> {
let mut p = group::Pack::default()
.with_label(&format!("{}", "MyStruct"))
.with_align(fltk::enums::Align::Left | fltk::enums::Align::Top);
p.set_spacing(5);
let mut i = self.a.view();
if unsafe { !i.raw_user_data().is_null() } {
i.set_align(fltk::enums::Align::Left);
i.set_label("a");
}
let mut i = self.b.view();
if unsafe { !i.raw_user_data().is_null() } {
i.set_align(fltk::enums::Align::Left);
i.set_label("b");
}
let mut i = self.c.view();
if unsafe { !i.raw_user_data().is_null() } {
i.set_align(fltk::enums::Align::Left);
i.set_label("c");
}
p.end();
let parent = p.parent().unwrap();
p.resize(
parent.x() + (parent.width()/2), parent.y() + parent.h() / 9, parent.width() / 3, (3 * 30 + 5 * 3) as i32
);
p.auto_layout();
Box::new(p)
}
}
fn main() {
let my_struct = MyStruct::<f64>::default(); // <-- instantiate your struct
let a = app::App::default().with_scheme(app::Scheme::Gtk);
app::set_background_color(222, 222, 222);
let mut win = window::Window::default().with_size(400, 300);
let mut grp = group::Group::default()
.with_size(300, 200)
.center_of_parent();
let mut form = my_struct.generate(); // <-- generate the form
form.resize(form.x() - 50, form.y(), form.w() + 30, form.h());
grp.end();
grp.set_frame(enums::FrameType::EngravedFrame);
let mut btn = button::Button::default()
.with_label("print")
.with_size(80, 30)
.below_of(&grp, 5)
.center_x(&grp);
win.end();
win.show();
let v = form.get_prop("b"); // <-- get a single property
assert_eq!(v, Some("3.0".to_owned()));
btn.set_callback(move |_| {
println!("{:?}", form.get_props()); // <-- get a HashMap of the properties
});
a.run().unwrap();
} |
So does this mean I have to add FltkForm as a constraint for |
You only need to constrain T to FltkForm if you want to call generate on it, otherwise rustc will error out saying no method generate was found for T. You can use features to define types with different members, generics etc, you’ll have to duplicate them however under cfg(feature) annotations. Rust’s generics have limitations with macros unfortunately. Like fltk::widget_extends! macro can’t be used with generic structs. |
Due to all the limitations imposed by using FLTK in Rust wrappers + the limitations of generics + the limitations of macros = Not possible to do exactly what I was trying to. I think I will close this issue, as it is documented well here for anyone who wants to attempt something similar. |
I know this is likely fringe, but is this even possible?
The text was updated successfully, but these errors were encountered: