PistonDevelopers / conrod

An easy-to-use, 2D GUI library written entirely in Rust.
Other
3.35k stars 296 forks source link

Suggestion for simplification of examples #1182

Closed mpizenberg closed 6 years ago

mpizenberg commented 6 years ago

Hi, so as a beginner Rust dev, I am discovering conrod to create GUIs. Since the guide is not ready yet, I dove into the examples and was quite overwhelmed by the amount of boilerplate in those. My only experience in GUI is with the elm programming language so I might be a bit biased. Anyway, I created a helper module program holding a Program struct, with two public methods, new and run:

pub fn new(title: &str, width: u32, height: u32, refresh_time: std::time::Duration) -> Program { ... }

pub fn run<Img, F>(&mut self, image_map: &conrod::image::Map<Img>, f: &mut F) -> ()
where
    Img: std::ops::Deref + glium::TextureDimensions,
    for<'a> glium::glium::uniforms::Sampler<'a, Img>: glium::glium::uniforms::AsUniformValue,
    F: FnMut(&mut conrod::UiCell) -> (),

It works pretty well with the examples I've tested so far, which are hello_world, counter, image, select_list. As an example, the hello world becomes:

//! Hello World using conrod

#[macro_use]
extern crate conrod;
extern crate image;

mod program;

use conrod::backend::glium::glium;
use conrod::{color, widget, Colorable, Positionable, Widget};

const WIDTH: u32 = 620;
const HEIGHT: u32 = 480;
const FONT_PATH: &str = "data/fonts/NotoSans/NotoSans-Regular.ttf";

fn main() {
    // Init the program
    let mut prog = program::Program::new(
        "Conrod Hello World",
        WIDTH,
        HEIGHT,
        std::time::Duration::from_millis(16),
    );

    // Add a `Font` to the `Ui`'s `font::Map` from file.
    prog.ui.fonts.insert_from_file(FONT_PATH).unwrap();

    // The hash map containing our images (none here).
    let image_map = conrod::image::Map::<glium::texture::Texture2d>::new();

    // Create our widgets.
    widget_ids!(struct Ids { text });
    let ids = Ids::new(prog.ui.widget_id_generator());

    let mut my_widgets = |ui: &mut conrod::UiCell| {
        widget::Text::new("Hello World!")
            .middle_of(ui.window)
            .color(color::WHITE)
            .font_size(32)
            .set(ids.text, ui);
    };

    // Run forever our program.
    prog.run(&image_map, &mut my_widgets);
}

I find it more approachable for newcomers but wanted to ask your feedback on this. The code for the program module and those rewritten examples is here: https://github.com/mpizenberg/computer-vision-rs/tree/master/examples. Feel free to reuse it however it pleases you ;)

Cheers, Matthieu

mitchmindtree commented 6 years ago

@mpizenberg thanks for the input!

I'm aware that there is a lot of boilerplate involved in raw conrod projects - there are a few reasons for this. A long time ago we had higher-level APIs similar to what you suggest in each backend but we ran into problems where people had different ideas about the way that event loops should be handled and we did not have enough dedication from contributors to maintain these different platform specific APIs. Users required more and more features and control over the event loop which required more platform-specific code in each backend and things felt to me like they were beginning to get a little out of hand. As a result I decided to strip conrod back to a "simpler" core which decidedly avoids supporting event loop abstractions. This made it more possible for me to keep up with conrod and moved the more opinionated event-loop related decisions and work out of conrod and into the hands of the users.

In summary, I totally agree that there is room for a much simpler API, however I think this should be the role of a downstream crate rather than conrod itself. As an example of this, I'm working on a creative coding framework called nannou which wraps conrod with a simpler UI API. The simple_ui.rs aims to demonstrate its usage. You may actually notice some similarities to elm's "model -> update -> view" approach as it was certainly part of the inspiration!

mpizenberg commented 6 years ago

Thanks for the thoughtful answer! I totally get the explanation. I think my expectations were different because I didn't have the context. Context that could be useful to add in the "Running the Conrod Examples" section of chapter 2.

Nannou does have a very familiar approach :). I'm currently working on a computer vision project and will need visualizations similar to what we can see in this video: https://youtu.be/C6-xwSOOdqQ. So mainly images and 3D point cloud + camera visuals. Do you think that is something I can achieve more easily with nannou?