PistonDevelopers / conrod

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

Add a `Batch` (or better name) Widget that allows for instantiating a list of graphics primitives without requiring unique `widget::Id`s and positions within the widget_graph for each one. #841

Open mitchmindtree opened 7 years ago

mitchmindtree commented 7 years ago

At the moment, instantiating graphics primitives like Rectangle or Line requires that each has its own unique slot within the widget_graph, and in turn requires they have their own widget::Ids and other associated widget information. This is fine and useful for most cases, however can potentially cause trouble when a user requires instantiating thousands or more of them as discussed here. In cases like this, it would be much more efficient to allow the user to instantiate a single widget that could represent a whole list of graphics primitives.

I can picture this widget being something like Batch<T> where T is some graphics primitive.

Each primitive in the list would then be returned as render::Primitives when drawing the Ui so that they can be rendered/optimised along with the rest of the Ui's graphics.

cc @Boscop

leroycep commented 7 years ago

What specific restrictions would apply to this? Would you still be able to set all the different attributes to the widgets? I haven't looked too closely at conrod's core, but the main advantages to this that I can see are:

  1. An easy way to place a dynamic amount of widgets
  2. A way to tell conrod to not track "extra" data for widgets

Would this make the id list macro syntax obsolete?

mitchmindtree commented 7 years ago

Would you still be able to set all the different attributes to the widgets?

This would specifically be for graphics primitives and you'd only be able to specify attributes related to the graphics for that primitive (i.e. position, size, color, etc).

Would this make the id list macro syntax obsolete?

For many cases it would, but it would still be necessary for instantiating a dynamic number of non-graphics-primitive widgets.

It sounds like you have something more general in mind, which could also be useful! I've considered adding something like a Group widget, where all it does is generate a number of Ids that you specify and provide them in a iterator type widget event, something like

for id in Group::new(20).set(BUTTONS, ui) {
    // instantiate each button with unique position, etc
}

I haven't got around to it as I wasn't sure if it would be worth it considering this would mean Group would need a place within the widget_graph (to store and re-use the Ids), whereas widget::id::List does not and isn't too tricky to use. However, looking at that example, it does look like it could be nice to have as a more ergonomic option. Might be worth opening another issue for this.

I also have some other ideas for reducing the size of the conrod::graph::Container (this is how widget's are stored within the widget_graph). At the moment, the Container stores a lot of redundant information for most widgets, including:

floating: HashSet<widget::Id>,
scroll_x: HashMap<widget::Id, scroll::State<X>>,
scroll_y: HashMap<widget::Id, scroll::State<Y>>,
kid_area: HashMap<widget::Id, Rect>,
crop_kids: HashSet<widget::Id>,

within the Ui. This way we only pay space for those that are scrollable/floating/cropping and we can remove those fields from the Container. Anyways, this is probably also better as a separate issue!

tl8roy commented 7 years ago

So I have actually done this for both a list and a keypad. While tracking ids, labels and button click action wasn't the easiest thing to deal with (Excel and Copy/Paste works wonders), the hardest this was positioning. I abused the down_from() and managed to get everything looking nice.

The advantage I had was that everything is static and can be somewhat hard coded. Implementing the list and widgets 'on the fly' is not something that I would want to do at the moment.