From ab51819bc1bdbe310793bb1f7e27f8969bedbdaf Mon Sep 17 00:00:00 2001 From: Tom Daffin Date: Sat, 25 May 2019 17:36:55 -0600 Subject: [PATCH 1/8] Refactor shared examples to make it easier to add more --- backends/conrod_example_shared/src/lib.rs | 456 +++++++++--------- backends/conrod_gfx/examples/all_winit_gfx.rs | 6 +- .../conrod_glium/examples/all_winit_glium.rs | 10 +- .../examples/all_winit_glium_threaded.rs | 5 +- .../examples/all_piston_window.rs | 6 +- .../examples/all_winit_vulkano.rs | 6 +- 6 files changed, 253 insertions(+), 236 deletions(-) diff --git a/backends/conrod_example_shared/src/lib.rs b/backends/conrod_example_shared/src/lib.rs index cd1a2586e..2495ccd7a 100644 --- a/backends/conrod_example_shared/src/lib.rs +++ b/backends/conrod_example_shared/src/lib.rs @@ -13,6 +13,9 @@ #[macro_use] extern crate conrod_core; extern crate rand; +use conrod_core::{widget, Colorable, Labelable, Positionable, Rect, Scalar, Sizeable, Ui, UiCell, Widget}; +use std::iter::once; + pub const WIN_W: u32 = 600; pub const WIN_H: u32 = 420; @@ -100,238 +103,249 @@ widget_ids! { } } +pub struct Gui { + ids: Ids, +} + +const MARGIN: Scalar = 30.0; +const SHAPE_GAP: Scalar = 50.0; +const TITLE_SIZE: conrod_core::FontSize = 42; +const SUBTITLE_SIZE: conrod_core::FontSize = 32; -/// Instantiate a GUI demonstrating every widget available in conrod. -pub fn gui(ui: &mut conrod_core::UiCell, ids: &Ids, app: &mut DemoApp) { - use conrod_core::{widget, Colorable, Labelable, Positionable, Sizeable, Widget}; - use std::iter::once; - - const MARGIN: conrod_core::Scalar = 30.0; - const SHAPE_GAP: conrod_core::Scalar = 50.0; - const TITLE_SIZE: conrod_core::FontSize = 42; - const SUBTITLE_SIZE: conrod_core::FontSize = 32; - - // `Canvas` is a widget that provides some basic functionality for laying out children widgets. - // By default, its size is the size of the window. We'll use this as a background for the - // following widgets, as well as a scrollable container for the children widgets. - const TITLE: &'static str = "All Widgets"; - widget::Canvas::new().pad(MARGIN).scroll_kids_vertically().set(ids.canvas, ui); - - - //////////////// - ///// TEXT ///// - //////////////// - - - // We'll demonstrate the `Text` primitive widget by using it to draw a title and an - // introduction to the example. - widget::Text::new(TITLE).font_size(TITLE_SIZE).mid_top_of(ids.canvas).set(ids.title, ui); - - const INTRODUCTION: &'static str = - "This example aims to demonstrate all widgets that are provided by conrod.\ - \n\nThe widget that you are currently looking at is the Text widget. The Text widget \ - is one of several special \"primitive\" widget types which are used to construct \ - all other widget types. These types are \"special\" in the sense that conrod knows \ - how to render them via `conrod_core::render::Primitive`s.\ - \n\nScroll down to see more widgets!"; - widget::Text::new(INTRODUCTION) - .padded_w_of(ids.canvas, MARGIN) - .down(60.0) - .align_middle_x_of(ids.canvas) - .center_justify() - .line_spacing(5.0) - .set(ids.introduction, ui); - - - //////////////////////////// - ///// Lines and Shapes ///// - //////////////////////////// - - - widget::Text::new("Lines and Shapes") - .down(70.0) - .align_middle_x_of(ids.canvas) - .font_size(SUBTITLE_SIZE) - .set(ids.shapes_title, ui); - - // Lay out the shapes in two horizontal columns. - // - // TODO: Have conrod provide an auto-flowing, fluid-list widget that is more adaptive for these - // sorts of situations. - widget::Canvas::new() - .down(0.0) - .align_middle_x_of(ids.canvas) - .kid_area_w_of(ids.canvas) - .h(360.0) - .color(conrod_core::color::TRANSPARENT) - .pad(MARGIN) - .flow_down(&[ - (ids.shapes_left_col, widget::Canvas::new()), - (ids.shapes_right_col, widget::Canvas::new()), - ]) - .set(ids.shapes_canvas, ui); - - let shapes_canvas_rect = ui.rect_of(ids.shapes_canvas).unwrap(); - let w = shapes_canvas_rect.w(); - let h = shapes_canvas_rect.h() * 5.0 / 6.0; - let radius = 10.0; - widget::RoundedRectangle::fill([w, h], radius) - .color(conrod_core::color::CHARCOAL.alpha(0.25)) - .middle_of(ids.shapes_canvas) - .set(ids.rounded_rectangle, ui); - - let start = [-40.0, -40.0]; - let end = [40.0, 40.0]; - widget::Line::centred(start, end).mid_left_of(ids.shapes_left_col).set(ids.line, ui); - - let left = [-40.0, -40.0]; - let top = [0.0, 40.0]; - let right = [40.0, -40.0]; - let points = once(left).chain(once(top)).chain(once(right)); - widget::PointPath::centred(points).right(SHAPE_GAP).set(ids.point_path, ui); - - widget::Rectangle::fill([80.0, 80.0]).right(SHAPE_GAP).set(ids.rectangle_fill, ui); - - widget::Rectangle::outline([80.0, 80.0]).right(SHAPE_GAP).set(ids.rectangle_outline, ui); - - let bl = [-40.0, -40.0]; - let tl = [-20.0, 40.0]; - let tr = [20.0, 40.0]; - let br = [40.0, -40.0]; - let points = once(bl).chain(once(tl)).chain(once(tr)).chain(once(br)); - widget::Polygon::centred_fill(points).mid_left_of(ids.shapes_right_col).set(ids.trapezoid, ui); - - widget::Oval::fill([40.0, 80.0]).right(SHAPE_GAP + 20.0).align_middle_y().set(ids.oval_fill, ui); - - widget::Oval::outline([80.0, 40.0]).right(SHAPE_GAP + 20.0).align_middle_y().set(ids.oval_outline, ui); - - widget::Circle::fill(40.0).right(SHAPE_GAP).align_middle_y().set(ids.circle, ui); - - - ///////////////// - ///// Image ///// - ///////////////// - - - widget::Text::new("Image") - .down_from(ids.shapes_canvas, MARGIN) - .align_middle_x_of(ids.canvas) - .font_size(SUBTITLE_SIZE) - .set(ids.image_title, ui); - - const LOGO_SIDE: conrod_core::Scalar = 144.0; - widget::Image::new(app.rust_logo) - .w_h(LOGO_SIDE, LOGO_SIDE) - .down(60.0) - .align_middle_x_of(ids.canvas) - .set(ids.rust_logo, ui); - - - ///////////////////////////////// - ///// Button, XYPad, Toggle ///// - ///////////////////////////////// - - - widget::Text::new("Button, XYPad and Toggle") - .down_from(ids.rust_logo, 60.0) - .align_middle_x_of(ids.canvas) - .font_size(SUBTITLE_SIZE) - .set(ids.button_title, ui); - - let ball_x_range = ui.kid_area_of(ids.canvas).unwrap().w(); - let ball_y_range = ui.h_of(ui.window).unwrap() * 0.5; - let min_x = -ball_x_range / 3.0; - let max_x = ball_x_range / 3.0; - let min_y = -ball_y_range / 3.0; - let max_y = ball_y_range / 3.0; - let side = 130.0; - - for _press in widget::Button::new() - .label("PRESS ME") - .mid_left_with_margin_on(ids.canvas, MARGIN) - .down_from(ids.button_title, 60.0) - .w_h(side, side) - .set(ids.button, ui) - { - let x = rand::random::() * (max_x - min_x) - max_x; - let y = rand::random::() * (max_y - min_y) - max_y; - app.ball_xy = [x, y]; +impl Gui { + pub fn new(ui: &mut Ui) -> Self { + Self { + ids: Ids::new(ui.widget_id_generator()), + } } - for (x, y) in widget::XYPad::new(app.ball_xy[0], min_x, max_x, - app.ball_xy[1], min_y, max_y) - .label("BALL XY") - .wh_of(ids.button) - .align_middle_y_of(ids.button) - .align_middle_x_of(ids.canvas) - .parent(ids.canvas) - .set(ids.xy_pad, ui) - { - app.ball_xy = [x, y]; + /// Instantiate a GUI demonstrating every widget available in conrod. + pub fn update(&self, ui: &mut UiCell, app: &mut DemoApp) { + let ids = &self.ids; + + // `Canvas` is a widget that provides some basic functionality for laying out children widgets. + // By default, its size is the size of the window. We'll use this as a background for the + // following widgets, as well as a scrollable container for the children widgets. + widget::Canvas::new().pad(MARGIN).scroll_kids_vertically().set(ids.canvas, ui); + + self.update_text(ui); + + self.update_lines_and_shapes(ui); + + self.update_image(ui, app); + + let ball_x_range = ui.kid_area_of(ids.canvas).unwrap().w(); + let ball_y_range = ui.h_of(ui.window).unwrap() * 0.5; + let rect = Rect::from_xy_dim([0.0, 0.0], [ball_x_range * 2.0 / 3.0, ball_y_range * 2.0 / 3.0]); + let side = 130.0; + + self.update_button_xy_pad_toggle(ui, app, &rect, side); + + self.update_number_dialer_plotpath(ui, app, &rect, side); + + ///////////////////// + ///// Scrollbar ///// + ///////////////////// + + widget::Scrollbar::y_axis(ids.canvas).auto_hide(true).set(ids.canvas_scrollbar, ui); } - let is_white = app.ball_color == conrod_core::color::WHITE; - let label = if is_white { "WHITE" } else { "BLACK" }; - for is_white in widget::Toggle::new(is_white) - .label(label) - .label_color(if is_white { conrod_core::color::WHITE } else { conrod_core::color::LIGHT_CHARCOAL }) - .mid_right_with_margin_on(ids.canvas, MARGIN) - .align_middle_y_of(ids.button) - .set(ids.toggle, ui) - { - app.ball_color = if is_white { conrod_core::color::WHITE } else { conrod_core::color::BLACK }; + fn update_text(&self, ui: &mut conrod_core::UiCell){ + let ids = &self.ids; + + // We'll demonstrate the `Text` primitive widget by using it to draw a title and an + // introduction to the example. + const TITLE: &'static str = "All Widgets"; + widget::Text::new(TITLE).font_size(TITLE_SIZE).mid_top_of(ids.canvas).set(ids.title, ui); + + const INTRODUCTION: &'static str = + "This example aims to demonstrate all widgets that are provided by conrod.\ + \n\nThe widget that you are currently looking at is the Text widget. The Text widget \ + is one of several special \"primitive\" widget types which are used to construct \ + all other widget types. These types are \"special\" in the sense that conrod knows \ + how to render them via `conrod_core::render::Primitive`s.\ + \n\nScroll down to see more widgets!"; + widget::Text::new(INTRODUCTION) + .padded_w_of(ids.canvas, MARGIN) + .down(60.0) + .align_middle_x_of(ids.canvas) + .center_justify() + .line_spacing(5.0) + .set(ids.introduction, ui); } - let ball_x = app.ball_xy[0]; - let ball_y = app.ball_xy[1] - max_y - side * 0.5 - MARGIN; - widget::Circle::fill(20.0) - .color(app.ball_color) - .x_y_relative_to(ids.xy_pad, ball_x, ball_y) - .set(ids.ball, ui); - - - ////////////////////////////////// - ///// NumberDialer, PlotPath ///// - ////////////////////////////////// - - - widget::Text::new("NumberDialer and PlotPath") - .down_from(ids.xy_pad, max_y - min_y + side * 0.5 + MARGIN) - .align_middle_x_of(ids.canvas) - .font_size(SUBTITLE_SIZE) - .set(ids.dialer_title, ui); - - // Use a `NumberDialer` widget to adjust the frequency of the sine wave below. - let min = 0.5; - let max = 200.0; - let decimal_precision = 1; - for new_freq in widget::NumberDialer::new(app.sine_frequency, min, max, decimal_precision) - .down(60.0) - .align_middle_x_of(ids.canvas) - .w_h(160.0, 40.0) - .label("F R E Q") - .set(ids.number_dialer, ui) - { - app.sine_frequency = new_freq; + fn update_lines_and_shapes(&self, ui: &mut conrod_core::UiCell){ + let ids = &self.ids; + + widget::Text::new("Lines and Shapes") + .down(70.0) + .align_middle_x_of(ids.canvas) + .font_size(SUBTITLE_SIZE) + .set(ids.shapes_title, ui); + + // Lay out the shapes in two horizontal columns. + // + // TODO: Have conrod provide an auto-flowing, fluid-list widget that is more adaptive for these + // sorts of situations. + widget::Canvas::new() + .down(0.0) + .align_middle_x_of(ids.canvas) + .kid_area_w_of(ids.canvas) + .h(360.0) + .color(conrod_core::color::TRANSPARENT) + .pad(MARGIN) + .flow_down(&[ + (ids.shapes_left_col, widget::Canvas::new()), + (ids.shapes_right_col, widget::Canvas::new()), + ]) + .set(ids.shapes_canvas, ui); + + let shapes_canvas_rect = ui.rect_of(ids.shapes_canvas).unwrap(); + let w = shapes_canvas_rect.w(); + let h = shapes_canvas_rect.h() * 5.0 / 6.0; + let radius = 10.0; + widget::RoundedRectangle::fill([w, h], radius) + .color(conrod_core::color::CHARCOAL.alpha(0.25)) + .middle_of(ids.shapes_canvas) + .set(ids.rounded_rectangle, ui); + + let start = [-40.0, -40.0]; + let end = [40.0, 40.0]; + widget::Line::centred(start, end).mid_left_of(ids.shapes_left_col).set(ids.line, ui); + + let left = [-40.0, -40.0]; + let top = [0.0, 40.0]; + let right = [40.0, -40.0]; + let points = once(left).chain(once(top)).chain(once(right)); + widget::PointPath::centred(points).right(SHAPE_GAP).set(ids.point_path, ui); + + widget::Rectangle::fill([80.0, 80.0]).right(SHAPE_GAP).set(ids.rectangle_fill, ui); + + widget::Rectangle::outline([80.0, 80.0]).right(SHAPE_GAP).set(ids.rectangle_outline, ui); + + let bl = [-40.0, -40.0]; + let tl = [-20.0, 40.0]; + let tr = [20.0, 40.0]; + let br = [40.0, -40.0]; + let points = once(bl).chain(once(tl)).chain(once(tr)).chain(once(br)); + widget::Polygon::centred_fill(points).mid_left_of(ids.shapes_right_col).set(ids.trapezoid, ui); + + widget::Oval::fill([40.0, 80.0]).right(SHAPE_GAP + 20.0).align_middle_y().set(ids.oval_fill, ui); + + widget::Oval::outline([80.0, 40.0]).right(SHAPE_GAP + 20.0).align_middle_y().set(ids.oval_outline, ui); + + widget::Circle::fill(40.0).right(SHAPE_GAP).align_middle_y().set(ids.circle, ui); + } + + fn update_image(&self, ui: &mut conrod_core::UiCell, app: &mut DemoApp){ + let ids = &self.ids; + + widget::Text::new("Image") + .down_from(ids.shapes_canvas, MARGIN) + .align_middle_x_of(ids.canvas) + .font_size(SUBTITLE_SIZE) + .set(ids.image_title, ui); + + const LOGO_SIDE: conrod_core::Scalar = 144.0; + widget::Image::new(app.rust_logo) + .w_h(LOGO_SIDE, LOGO_SIDE) + .down(60.0) + .align_middle_x_of(ids.canvas) + .set(ids.rust_logo, ui); } - // Use the `PlotPath` widget to display a sine wave. - let min_x = 0.0; - let max_x = std::f32::consts::PI * 2.0 * app.sine_frequency; - let min_y = -1.0; - let max_y = 1.0; - widget::PlotPath::new(min_x, max_x, min_y, max_y, f32::sin) - .kid_area_w_of(ids.canvas) - .h(240.0) - .down(60.0) - .align_middle_x_of(ids.canvas) - .set(ids.plot_path, ui); + fn update_button_xy_pad_toggle(&self, ui: &mut conrod_core::UiCell, app: &mut DemoApp, + rect: &Rect, side: f64) + { + let ids = &self.ids; + + widget::Text::new("Button, XYPad and Toggle") + .down_from(ids.rust_logo, 60.0) + .align_middle_x_of(ids.canvas) + .font_size(SUBTITLE_SIZE) + .set(ids.button_title, ui); + + for _press in widget::Button::new() + .label("PRESS ME") + .mid_left_with_margin_on(ids.canvas, MARGIN) + .down_from(ids.button_title, 60.0) + .w_h(side, side) + .set(ids.button, ui) + { + let x = rand::random::() * (rect.x.end - rect.x.start) - rect.x.end; + let y = rand::random::() * (rect.y.end - rect.y.start) - rect.y.end; + app.ball_xy = [x, y]; + } + + for (x, y) in widget::XYPad::new(app.ball_xy[0], rect.x.start, rect.x.end, + app.ball_xy[1], rect.y.start, rect.y.end) + .label("BALL XY") + .wh_of(ids.button) + .align_middle_y_of(ids.button) + .align_middle_x_of(ids.canvas) + .parent(ids.canvas) + .set(ids.xy_pad, ui) + { + app.ball_xy = [x, y]; + } + + let is_white = app.ball_color == conrod_core::color::WHITE; + let label = if is_white { "WHITE" } else { "BLACK" }; + for is_white in widget::Toggle::new(is_white) + .label(label) + .label_color(if is_white { conrod_core::color::WHITE } else { conrod_core::color::LIGHT_CHARCOAL }) + .mid_right_with_margin_on(ids.canvas, MARGIN) + .align_middle_y_of(ids.button) + .set(ids.toggle, ui) + { + app.ball_color = if is_white { conrod_core::color::WHITE } else { conrod_core::color::BLACK }; + } + let ball_x = app.ball_xy[0]; + let ball_y = app.ball_xy[1] - rect.y.end - side * 0.5 - MARGIN; + widget::Circle::fill(20.0) + .color(app.ball_color) + .x_y_relative_to(ids.xy_pad, ball_x, ball_y) + .set(ids.ball, ui); + } - ///////////////////// - ///// Scrollbar ///// - ///////////////////// + fn update_number_dialer_plotpath(&self, ui: &mut conrod_core::UiCell, app: &mut DemoApp, + rect: &Rect, side: f64) + { + let ids = &self.ids; + + widget::Text::new("NumberDialer and PlotPath") + .down_from(ids.xy_pad, rect.y.end - rect.y.start + side * 0.5 + MARGIN) + .align_middle_x_of(ids.canvas) + .font_size(SUBTITLE_SIZE) + .set(ids.dialer_title, ui); + + // Use a `NumberDialer` widget to adjust the frequency of the sine wave below. + let min = 0.5; + let max = 200.0; + let decimal_precision = 1; + for new_freq in widget::NumberDialer::new(app.sine_frequency, min, max, decimal_precision) + .down(60.0) + .align_middle_x_of(ids.canvas) + .w_h(160.0, 40.0) + .label("F R E Q") + .set(ids.number_dialer, ui) + { + app.sine_frequency = new_freq; + } + // Use the `PlotPath` widget to display a sine wave. + let min_x = 0.0; + let max_x = std::f32::consts::PI * 2.0 * app.sine_frequency; + let min_y = -1.0; + let max_y = 1.0; + widget::PlotPath::new(min_x, max_x, min_y, max_y, f32::sin) + .kid_area_w_of(ids.canvas) + .h(240.0) + .down(60.0) + .align_middle_x_of(ids.canvas) + .set(ids.plot_path, ui); + } - widget::Scrollbar::y_axis(ids.canvas).auto_hide(true).set(ids.canvas_scrollbar, ui); } + diff --git a/backends/conrod_gfx/examples/all_winit_gfx.rs b/backends/conrod_gfx/examples/all_winit_gfx.rs index c7a1e76cd..c75505003 100644 --- a/backends/conrod_gfx/examples/all_winit_gfx.rs +++ b/backends/conrod_gfx/examples/all_winit_gfx.rs @@ -65,7 +65,7 @@ fn main() { let mut ui = conrod_core::UiBuilder::new([WIN_W as f64, WIN_H as f64]) .theme(conrod_example_shared::theme()) .build(); - let ids = conrod_example_shared::Ids::new(ui.widget_id_generator()); + let gui = conrod_example_shared::Gui::new(&mut ui); // Load font from file let assets = find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap(); @@ -167,8 +167,8 @@ fn main() { // Update widgets if any event has happened if ui.global_input().events().next().is_some() { - let mut ui = ui.set_widgets(); - conrod_example_shared::gui(&mut ui, &ids, &mut app); + let mut ui = &mut ui.set_widgets(); + gui.update(&mut ui, &mut app); } } } diff --git a/backends/conrod_glium/examples/all_winit_glium.rs b/backends/conrod_glium/examples/all_winit_glium.rs index 96a4dd76b..5f4ab225b 100644 --- a/backends/conrod_glium/examples/all_winit_glium.rs +++ b/backends/conrod_glium/examples/all_winit_glium.rs @@ -27,10 +27,11 @@ fn main() { let display = support::GliumDisplayWinitWrapper(display); // Construct our `Ui`. - let mut ui = conrod_core::UiBuilder::new([WIN_W as f64, WIN_H as f64]).theme(conrod_example_shared::theme()).build(); + let mut ui = conrod_core::UiBuilder::new([WIN_W as f64, WIN_H as f64]) + .theme(conrod_example_shared::theme()) + .build(); - // The `widget::Id` of each widget instantiated in `conrod_example_shared::gui`. - let ids = conrod_example_shared::Ids::new(ui.widget_id_generator()); + let gui = conrod_example_shared::Gui::new(&mut ui); // Add a `Font` to the `Ui`'s `font::Map` from file. let assets = find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap(); @@ -101,7 +102,8 @@ fn main() { } // Instantiate a GUI demonstrating every widget type provided by conrod. - conrod_example_shared::gui(&mut ui.set_widgets(), &ids, &mut app); + let mut ui = &mut ui.set_widgets(); + gui.update(&mut ui, &mut app); // Draw the `Ui`. if let Some(primitives) = ui.draw_if_changed() { diff --git a/backends/conrod_glium/examples/all_winit_glium_threaded.rs b/backends/conrod_glium/examples/all_winit_glium_threaded.rs index 9f54b3419..3b14f8c36 100644 --- a/backends/conrod_glium/examples/all_winit_glium_threaded.rs +++ b/backends/conrod_glium/examples/all_winit_glium_threaded.rs @@ -80,7 +80,7 @@ fn main() { let mut app = conrod_example_shared::DemoApp::new(rust_logo); // The `widget::Id` of each widget instantiated in `conrod_example_shared::gui`. - let ids = conrod_example_shared::Ids::new(ui.widget_id_generator()); + let gui = conrod_example_shared::Gui::new(&mut ui); // Many widgets require another frame to finish drawing after clicks or hovers, so we // insert an update into the conrod loop using this `bool` after each event. @@ -110,7 +110,8 @@ fn main() { } // Instantiate a GUI demonstrating every widget type provided by conrod. - conrod_example_shared::gui(&mut ui.set_widgets(), &ids, &mut app); + let mut ui = &mut ui.set_widgets(); + gui.update(&mut ui, &mut app); // Render the `Ui` to a list of primitives that we can send to the main thread for // display. Wakeup `winit` for rendering. diff --git a/backends/conrod_piston/examples/all_piston_window.rs b/backends/conrod_piston/examples/all_piston_window.rs index 0b6ae9968..46480c111 100644 --- a/backends/conrod_piston/examples/all_piston_window.rs +++ b/backends/conrod_piston/examples/all_piston_window.rs @@ -54,7 +54,7 @@ pub fn main() { }; // Instantiate the generated list of widget identifiers. - let ids = conrod_example_shared::Ids::new(ui.widget_id_generator()); + let gui = conrod_example_shared::Gui::new(&mut ui); // Load the rust logo from file to a piston_window texture. let rust_logo: G2dTexture = { @@ -84,8 +84,8 @@ pub fn main() { } event.update(|_| { - let mut ui = ui.set_widgets(); - conrod_example_shared::gui(&mut ui, &ids, &mut app); + let mut ui = &mut ui.set_widgets(); + gui.update(&mut ui, &mut app); }); window.draw_2d(&event, |context, graphics| { diff --git a/backends/conrod_vulkano/examples/all_winit_vulkano.rs b/backends/conrod_vulkano/examples/all_winit_vulkano.rs index d8b124dad..f100fbd65 100644 --- a/backends/conrod_vulkano/examples/all_winit_vulkano.rs +++ b/backends/conrod_vulkano/examples/all_winit_vulkano.rs @@ -56,7 +56,7 @@ fn main() { let mut ui = conrod_core::UiBuilder::new([WIN_W as f64, WIN_H as f64]) .theme(conrod_example_shared::theme()) .build(); - let ids = conrod_example_shared::Ids::new(ui.widget_id_generator()); + let gui = conrod_example_shared::Gui::new(&mut ui); // Load font from file let assets = find_folder::Search::KidsThenParents(3, 5) @@ -236,8 +236,8 @@ fn main() { // Update widgets if any event has happened if ui.global_input().events().next().is_some() { - let mut ui = ui.set_widgets(); - conrod_example_shared::gui(&mut ui, &ids, &mut app); + let mut ui = &mut ui.set_widgets(); + gui.update(&mut ui, &mut app); } } } From a037e27108893b503c21e6fbdc1874dbd77a9a60 Mon Sep 17 00:00:00 2001 From: Tom Daffin Date: Sat, 25 May 2019 18:48:51 -0600 Subject: [PATCH 2/8] Move button_xy_pad_toggle widgets out into a separate struct --- .../src/button_xy_pad_toggle.rs | 104 ++++++++++++++++++ backends/conrod_example_shared/src/layout.rs | 6 + backends/conrod_example_shared/src/lib.rs | 85 ++------------ 3 files changed, 122 insertions(+), 73 deletions(-) create mode 100644 backends/conrod_example_shared/src/button_xy_pad_toggle.rs create mode 100644 backends/conrod_example_shared/src/layout.rs diff --git a/backends/conrod_example_shared/src/button_xy_pad_toggle.rs b/backends/conrod_example_shared/src/button_xy_pad_toggle.rs new file mode 100644 index 000000000..4e8ce9cbb --- /dev/null +++ b/backends/conrod_example_shared/src/button_xy_pad_toggle.rs @@ -0,0 +1,104 @@ + +use conrod_core::{ + Colorable, + Widget, + Labelable, + Positionable, + Rect, + Sizeable, + Ui, + UiCell, + widget, +}; + +use layout::*; + +widget_ids! { + pub struct Ids { + button_title, + button, + xy_pad, + toggle, + ball, + } +} + +pub struct GuiState { + ball_xy: conrod_core::Point, + ball_color: conrod_core::Color, +} + +impl GuiState { + pub fn new() -> Self { + Self { + ball_xy: [0.0, 0.0], + ball_color: conrod_core::color::WHITE, + } + } +} + +pub struct Gui { + ids: Ids, +} + +impl Gui { + pub fn new(ui: &mut Ui) -> Self { + Self { + ids: Ids::new(ui.widget_id_generator()), + } + } + + pub fn update(&self, ui: &mut UiCell, state: &mut GuiState, canvas: widget::Id, rect: &Rect, side: f64) { + + let ids = &self.ids; + + widget::Text::new("Button, XYPad and Toggle") + .down(60.0) + .align_middle_x_of(canvas) + .font_size(SUBTITLE_SIZE) + .set(ids.button_title, ui); + + for _press in widget::Button::new() + .label("PRESS ME") + .mid_left_with_margin_on(canvas, MARGIN) + .down_from(ids.button_title, 60.0) + .w_h(side, side) + .set(ids.button, ui) + { + let x = rand::random::() * (rect.x.end - rect.x.start) - rect.x.end; + let y = rand::random::() * (rect.y.end - rect.y.start) - rect.y.end; + state.ball_xy = [x, y]; + } + + for (x, y) in widget::XYPad::new(state.ball_xy[0], rect.x.start, rect.x.end, + state.ball_xy[1], rect.y.start, rect.y.end) + .label("BALL XY") + .wh_of(ids.button) + .align_middle_y_of(ids.button) + .align_middle_x_of(canvas) + .parent(canvas) + .set(ids.xy_pad, ui) + { + state.ball_xy = [x, y]; + } + + let is_white = state.ball_color == conrod_core::color::WHITE; + let label = if is_white { "WHITE" } else { "BLACK" }; + for is_white in widget::Toggle::new(is_white) + .label(label) + .label_color(if is_white { conrod_core::color::WHITE } else { conrod_core::color::LIGHT_CHARCOAL }) + .mid_right_with_margin_on(canvas, MARGIN) + .align_middle_y_of(ids.button) + .set(ids.toggle, ui) + { + state.ball_color = if is_white { conrod_core::color::WHITE } else { conrod_core::color::BLACK }; + } + + let ball_x = state.ball_xy[0]; + let ball_y = state.ball_xy[1] - rect.y.end - side * 0.5 - MARGIN; + widget::Circle::fill(20.0) + .color(state.ball_color) + .x_y_relative_to(ids.xy_pad, ball_x, ball_y) + .set(ids.ball, ui); + } +} diff --git a/backends/conrod_example_shared/src/layout.rs b/backends/conrod_example_shared/src/layout.rs new file mode 100644 index 000000000..e747fff22 --- /dev/null +++ b/backends/conrod_example_shared/src/layout.rs @@ -0,0 +1,6 @@ +use conrod_core::Scalar; + +pub const MARGIN: Scalar = 30.0; +pub const SHAPE_GAP: Scalar = 50.0; +pub const TITLE_SIZE: conrod_core::FontSize = 42; +pub const SUBTITLE_SIZE: conrod_core::FontSize = 32; diff --git a/backends/conrod_example_shared/src/lib.rs b/backends/conrod_example_shared/src/lib.rs index 2495ccd7a..160525c4f 100644 --- a/backends/conrod_example_shared/src/lib.rs +++ b/backends/conrod_example_shared/src/lib.rs @@ -13,7 +13,12 @@ #[macro_use] extern crate conrod_core; extern crate rand; -use conrod_core::{widget, Colorable, Labelable, Positionable, Rect, Scalar, Sizeable, Ui, UiCell, Widget}; +mod layout; +mod button_xy_pad_toggle; + +use layout::*; + +use conrod_core::{widget, Colorable, Labelable, Positionable, Rect, Sizeable, Ui, UiCell, Widget}; use std::iter::once; pub const WIN_W: u32 = 600; @@ -21,8 +26,7 @@ pub const WIN_H: u32 = 420; /// A demonstration of some application state we want to control with a conrod GUI. pub struct DemoApp { - ball_xy: conrod_core::Point, - ball_color: conrod_core::Color, + button_xy_pad_toggle: button_xy_pad_toggle::GuiState, sine_frequency: f32, rust_logo: conrod_core::image::Id, } @@ -32,8 +36,7 @@ impl DemoApp { /// Simple constructor for the `DemoApp`. pub fn new(rust_logo: conrod_core::image::Id) -> Self { DemoApp { - ball_xy: [0.0, 0.0], - ball_color: conrod_core::color::WHITE, + button_xy_pad_toggle: button_xy_pad_toggle::GuiState::new(), sine_frequency: 1.0, rust_logo: rust_logo, } @@ -88,12 +91,6 @@ widget_ids! { // Image. image_title, rust_logo, - // Button, XyPad, Toggle. - button_title, - button, - xy_pad, - toggle, - ball, // NumberDialer, PlotPath dialer_title, number_dialer, @@ -105,17 +102,14 @@ widget_ids! { pub struct Gui { ids: Ids, + button_xy_pad_toggle: button_xy_pad_toggle::Gui, } -const MARGIN: Scalar = 30.0; -const SHAPE_GAP: Scalar = 50.0; -const TITLE_SIZE: conrod_core::FontSize = 42; -const SUBTITLE_SIZE: conrod_core::FontSize = 32; - impl Gui { pub fn new(ui: &mut Ui) -> Self { Self { ids: Ids::new(ui.widget_id_generator()), + button_xy_pad_toggle: button_xy_pad_toggle::Gui::new(ui), } } @@ -139,7 +133,7 @@ impl Gui { let rect = Rect::from_xy_dim([0.0, 0.0], [ball_x_range * 2.0 / 3.0, ball_y_range * 2.0 / 3.0]); let side = 130.0; - self.update_button_xy_pad_toggle(ui, app, &rect, side); + self.button_xy_pad_toggle.update(ui, &mut app.button_xy_pad_toggle, ids.canvas, &rect, side); self.update_number_dialer_plotpath(ui, app, &rect, side); @@ -254,68 +248,13 @@ impl Gui { .set(ids.rust_logo, ui); } - fn update_button_xy_pad_toggle(&self, ui: &mut conrod_core::UiCell, app: &mut DemoApp, - rect: &Rect, side: f64) - { - let ids = &self.ids; - - widget::Text::new("Button, XYPad and Toggle") - .down_from(ids.rust_logo, 60.0) - .align_middle_x_of(ids.canvas) - .font_size(SUBTITLE_SIZE) - .set(ids.button_title, ui); - - for _press in widget::Button::new() - .label("PRESS ME") - .mid_left_with_margin_on(ids.canvas, MARGIN) - .down_from(ids.button_title, 60.0) - .w_h(side, side) - .set(ids.button, ui) - { - let x = rand::random::() * (rect.x.end - rect.x.start) - rect.x.end; - let y = rand::random::() * (rect.y.end - rect.y.start) - rect.y.end; - app.ball_xy = [x, y]; - } - - for (x, y) in widget::XYPad::new(app.ball_xy[0], rect.x.start, rect.x.end, - app.ball_xy[1], rect.y.start, rect.y.end) - .label("BALL XY") - .wh_of(ids.button) - .align_middle_y_of(ids.button) - .align_middle_x_of(ids.canvas) - .parent(ids.canvas) - .set(ids.xy_pad, ui) - { - app.ball_xy = [x, y]; - } - - let is_white = app.ball_color == conrod_core::color::WHITE; - let label = if is_white { "WHITE" } else { "BLACK" }; - for is_white in widget::Toggle::new(is_white) - .label(label) - .label_color(if is_white { conrod_core::color::WHITE } else { conrod_core::color::LIGHT_CHARCOAL }) - .mid_right_with_margin_on(ids.canvas, MARGIN) - .align_middle_y_of(ids.button) - .set(ids.toggle, ui) - { - app.ball_color = if is_white { conrod_core::color::WHITE } else { conrod_core::color::BLACK }; - } - - let ball_x = app.ball_xy[0]; - let ball_y = app.ball_xy[1] - rect.y.end - side * 0.5 - MARGIN; - widget::Circle::fill(20.0) - .color(app.ball_color) - .x_y_relative_to(ids.xy_pad, ball_x, ball_y) - .set(ids.ball, ui); - } - fn update_number_dialer_plotpath(&self, ui: &mut conrod_core::UiCell, app: &mut DemoApp, rect: &Rect, side: f64) { let ids = &self.ids; widget::Text::new("NumberDialer and PlotPath") - .down_from(ids.xy_pad, rect.y.end - rect.y.start + side * 0.5 + MARGIN) + .down(rect.y.end - rect.y.start + side * 0.5 + MARGIN) .align_middle_x_of(ids.canvas) .font_size(SUBTITLE_SIZE) .set(ids.dialer_title, ui); From aeaef27ce9dda313b9d840c54690eb0ce6a2e83c Mon Sep 17 00:00:00 2001 From: Tom Daffin Date: Sat, 25 May 2019 20:47:49 -0600 Subject: [PATCH 3/8] Move shapes widgets out into a separate struct --- backends/conrod_example_shared/src/lib.rs | 91 ++-------------- backends/conrod_example_shared/src/shapes.rs | 109 +++++++++++++++++++ 2 files changed, 117 insertions(+), 83 deletions(-) create mode 100644 backends/conrod_example_shared/src/shapes.rs diff --git a/backends/conrod_example_shared/src/lib.rs b/backends/conrod_example_shared/src/lib.rs index 160525c4f..416acb7f0 100644 --- a/backends/conrod_example_shared/src/lib.rs +++ b/backends/conrod_example_shared/src/lib.rs @@ -14,12 +14,12 @@ extern crate rand; mod layout; +mod shapes; mod button_xy_pad_toggle; use layout::*; -use conrod_core::{widget, Colorable, Labelable, Positionable, Rect, Sizeable, Ui, UiCell, Widget}; -use std::iter::once; +use conrod_core::{widget, Labelable, Positionable, Rect, Sizeable, Ui, UiCell, Widget}; pub const WIN_W: u32 = 600; pub const WIN_H: u32 = 420; @@ -74,20 +74,6 @@ widget_ids! { // The title and introduction widgets. title, introduction, - // Shapes. - shapes_canvas, - rounded_rectangle, - shapes_left_col, - shapes_right_col, - shapes_title, - line, - point_path, - rectangle_fill, - rectangle_outline, - trapezoid, - oval_fill, - oval_outline, - circle, // Image. image_title, rust_logo, @@ -103,6 +89,7 @@ widget_ids! { pub struct Gui { ids: Ids, button_xy_pad_toggle: button_xy_pad_toggle::Gui, + shapes: shapes::Gui, } impl Gui { @@ -110,6 +97,7 @@ impl Gui { Self { ids: Ids::new(ui.widget_id_generator()), button_xy_pad_toggle: button_xy_pad_toggle::Gui::new(ui), + shapes: shapes::Gui::new(ui), } } @@ -124,9 +112,9 @@ impl Gui { self.update_text(ui); - self.update_lines_and_shapes(ui); + let last = self.shapes.update(ui, ids.canvas); - self.update_image(ui, app); + self.update_image(ui, app, last); let ball_x_range = ui.kid_area_of(ids.canvas).unwrap().w(); let ball_y_range = ui.h_of(ui.window).unwrap() * 0.5; @@ -168,74 +156,11 @@ impl Gui { .set(ids.introduction, ui); } - fn update_lines_and_shapes(&self, ui: &mut conrod_core::UiCell){ - let ids = &self.ids; - - widget::Text::new("Lines and Shapes") - .down(70.0) - .align_middle_x_of(ids.canvas) - .font_size(SUBTITLE_SIZE) - .set(ids.shapes_title, ui); - - // Lay out the shapes in two horizontal columns. - // - // TODO: Have conrod provide an auto-flowing, fluid-list widget that is more adaptive for these - // sorts of situations. - widget::Canvas::new() - .down(0.0) - .align_middle_x_of(ids.canvas) - .kid_area_w_of(ids.canvas) - .h(360.0) - .color(conrod_core::color::TRANSPARENT) - .pad(MARGIN) - .flow_down(&[ - (ids.shapes_left_col, widget::Canvas::new()), - (ids.shapes_right_col, widget::Canvas::new()), - ]) - .set(ids.shapes_canvas, ui); - - let shapes_canvas_rect = ui.rect_of(ids.shapes_canvas).unwrap(); - let w = shapes_canvas_rect.w(); - let h = shapes_canvas_rect.h() * 5.0 / 6.0; - let radius = 10.0; - widget::RoundedRectangle::fill([w, h], radius) - .color(conrod_core::color::CHARCOAL.alpha(0.25)) - .middle_of(ids.shapes_canvas) - .set(ids.rounded_rectangle, ui); - - let start = [-40.0, -40.0]; - let end = [40.0, 40.0]; - widget::Line::centred(start, end).mid_left_of(ids.shapes_left_col).set(ids.line, ui); - - let left = [-40.0, -40.0]; - let top = [0.0, 40.0]; - let right = [40.0, -40.0]; - let points = once(left).chain(once(top)).chain(once(right)); - widget::PointPath::centred(points).right(SHAPE_GAP).set(ids.point_path, ui); - - widget::Rectangle::fill([80.0, 80.0]).right(SHAPE_GAP).set(ids.rectangle_fill, ui); - - widget::Rectangle::outline([80.0, 80.0]).right(SHAPE_GAP).set(ids.rectangle_outline, ui); - - let bl = [-40.0, -40.0]; - let tl = [-20.0, 40.0]; - let tr = [20.0, 40.0]; - let br = [40.0, -40.0]; - let points = once(bl).chain(once(tl)).chain(once(tr)).chain(once(br)); - widget::Polygon::centred_fill(points).mid_left_of(ids.shapes_right_col).set(ids.trapezoid, ui); - - widget::Oval::fill([40.0, 80.0]).right(SHAPE_GAP + 20.0).align_middle_y().set(ids.oval_fill, ui); - - widget::Oval::outline([80.0, 40.0]).right(SHAPE_GAP + 20.0).align_middle_y().set(ids.oval_outline, ui); - - widget::Circle::fill(40.0).right(SHAPE_GAP).align_middle_y().set(ids.circle, ui); - } - - fn update_image(&self, ui: &mut conrod_core::UiCell, app: &mut DemoApp){ + fn update_image(&self, ui: &mut conrod_core::UiCell, app: &mut DemoApp, last: widget::Id){ let ids = &self.ids; widget::Text::new("Image") - .down_from(ids.shapes_canvas, MARGIN) + .down_from(last, MARGIN) .align_middle_x_of(ids.canvas) .font_size(SUBTITLE_SIZE) .set(ids.image_title, ui); diff --git a/backends/conrod_example_shared/src/shapes.rs b/backends/conrod_example_shared/src/shapes.rs new file mode 100644 index 000000000..1071eed8c --- /dev/null +++ b/backends/conrod_example_shared/src/shapes.rs @@ -0,0 +1,109 @@ + +use conrod_core::{ + Colorable, + Widget, + Positionable, + Sizeable, + Ui, + UiCell, + widget, +}; + +use layout::*; + +widget_ids! { + pub struct Ids { + shapes_canvas, + rounded_rectangle, + shapes_left_col, + shapes_right_col, + shapes_title, + line, + point_path, + rectangle_fill, + rectangle_outline, + trapezoid, + oval_fill, + oval_outline, + circle, + } +} + +pub struct Gui { + ids: Ids, +} + +impl Gui { + pub fn new(ui: &mut Ui) -> Self { + Self { + ids: Ids::new(ui.widget_id_generator()), + } + } + + pub fn update(&self, ui: &mut UiCell, canvas: widget::Id) -> widget::Id { + use std::iter::once; + + let ids = &self.ids; + + widget::Text::new("Lines and Shapes") + .down(70.0) + .align_middle_x_of(canvas) + .font_size(SUBTITLE_SIZE) + .set(ids.shapes_title, ui); + + // Lay out the shapes in two horizontal columns. + // + // TODO: Have conrod provide an auto-flowing, fluid-list widget that is more adaptive for these + // sorts of situations. + widget::Canvas::new() + .down(0.0) + .align_middle_x_of(canvas) + .kid_area_w_of(canvas) + .h(360.0) + .color(conrod_core::color::TRANSPARENT) + .pad(MARGIN) + .flow_down(&[ + (ids.shapes_left_col, widget::Canvas::new()), + (ids.shapes_right_col, widget::Canvas::new()), + ]) + .set(ids.shapes_canvas, ui); + + let shapes_canvas_rect = ui.rect_of(ids.shapes_canvas).unwrap(); + let w = shapes_canvas_rect.w(); + let h = shapes_canvas_rect.h() * 5.0 / 6.0; + let radius = 10.0; + widget::RoundedRectangle::fill([w, h], radius) + .color(conrod_core::color::CHARCOAL.alpha(0.25)) + .middle_of(ids.shapes_canvas) + .set(ids.rounded_rectangle, ui); + + let start = [-40.0, -40.0]; + let end = [40.0, 40.0]; + widget::Line::centred(start, end).mid_left_of(ids.shapes_left_col).set(ids.line, ui); + + let left = [-40.0, -40.0]; + let top = [0.0, 40.0]; + let right = [40.0, -40.0]; + let points = once(left).chain(once(top)).chain(once(right)); + widget::PointPath::centred(points).right(SHAPE_GAP).set(ids.point_path, ui); + + widget::Rectangle::fill([80.0, 80.0]).right(SHAPE_GAP).set(ids.rectangle_fill, ui); + + widget::Rectangle::outline([80.0, 80.0]).right(SHAPE_GAP).set(ids.rectangle_outline, ui); + + let bl = [-40.0, -40.0]; + let tl = [-20.0, 40.0]; + let tr = [20.0, 40.0]; + let br = [40.0, -40.0]; + let points = once(bl).chain(once(tl)).chain(once(tr)).chain(once(br)); + widget::Polygon::centred_fill(points).mid_left_of(ids.shapes_right_col).set(ids.trapezoid, ui); + + widget::Oval::fill([40.0, 80.0]).right(SHAPE_GAP + 20.0).align_middle_y().set(ids.oval_fill, ui); + + widget::Oval::outline([80.0, 40.0]).right(SHAPE_GAP + 20.0).align_middle_y().set(ids.oval_outline, ui); + + widget::Circle::fill(40.0).right(SHAPE_GAP).align_middle_y().set(ids.circle, ui); + + ids.shapes_canvas + } +} From e423126186287805e2764c7b45e77114c5df70c5 Mon Sep 17 00:00:00 2001 From: Tom Daffin Date: Sat, 25 May 2019 20:56:10 -0600 Subject: [PATCH 4/8] Fix layout --- .../src/button_xy_pad_toggle.rs | 6 ++++-- backends/conrod_example_shared/src/lib.rs | 13 +++++++------ backends/conrod_example_shared/src/shapes.rs | 3 ++- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/backends/conrod_example_shared/src/button_xy_pad_toggle.rs b/backends/conrod_example_shared/src/button_xy_pad_toggle.rs index 4e8ce9cbb..36f366aa2 100644 --- a/backends/conrod_example_shared/src/button_xy_pad_toggle.rs +++ b/backends/conrod_example_shared/src/button_xy_pad_toggle.rs @@ -48,8 +48,8 @@ impl Gui { } } - pub fn update(&self, ui: &mut UiCell, state: &mut GuiState, canvas: widget::Id, rect: &Rect, side: f64) { - + /// Returns id of widget that the next Gui should be down_from + pub fn update(&self, ui: &mut UiCell, state: &mut GuiState, canvas: widget::Id, rect: &Rect, side: f64) -> widget::Id { let ids = &self.ids; widget::Text::new("Button, XYPad and Toggle") @@ -100,5 +100,7 @@ impl Gui { .color(state.ball_color) .x_y_relative_to(ids.xy_pad, ball_x, ball_y) .set(ids.ball, ui); + + ids.xy_pad // Return id of widget that the next Gui should be down_from } } diff --git a/backends/conrod_example_shared/src/lib.rs b/backends/conrod_example_shared/src/lib.rs index 416acb7f0..dd59186df 100644 --- a/backends/conrod_example_shared/src/lib.rs +++ b/backends/conrod_example_shared/src/lib.rs @@ -19,7 +19,7 @@ mod button_xy_pad_toggle; use layout::*; -use conrod_core::{widget, Labelable, Positionable, Rect, Sizeable, Ui, UiCell, Widget}; +use conrod_core::{widget, Labelable, Positionable, Rect, Scalar, Sizeable, Ui, UiCell, Widget}; pub const WIN_W: u32 = 600; pub const WIN_H: u32 = 420; @@ -121,9 +121,10 @@ impl Gui { let rect = Rect::from_xy_dim([0.0, 0.0], [ball_x_range * 2.0 / 3.0, ball_y_range * 2.0 / 3.0]); let side = 130.0; - self.button_xy_pad_toggle.update(ui, &mut app.button_xy_pad_toggle, ids.canvas, &rect, side); - - self.update_number_dialer_plotpath(ui, app, &rect, side); + let last = self.button_xy_pad_toggle.update(ui, &mut app.button_xy_pad_toggle, ids.canvas, &rect, side); + + let space = rect.y.end - rect.y.start + side * 0.5 + MARGIN; + self.update_number_dialer_plotpath(ui, app, last, space); ///////////////////// ///// Scrollbar ///// @@ -174,12 +175,12 @@ impl Gui { } fn update_number_dialer_plotpath(&self, ui: &mut conrod_core::UiCell, app: &mut DemoApp, - rect: &Rect, side: f64) + last: widget::Id, space: Scalar) { let ids = &self.ids; widget::Text::new("NumberDialer and PlotPath") - .down(rect.y.end - rect.y.start + side * 0.5 + MARGIN) + .down_from(last, space) .align_middle_x_of(ids.canvas) .font_size(SUBTITLE_SIZE) .set(ids.dialer_title, ui); diff --git a/backends/conrod_example_shared/src/shapes.rs b/backends/conrod_example_shared/src/shapes.rs index 1071eed8c..70b884cbe 100644 --- a/backends/conrod_example_shared/src/shapes.rs +++ b/backends/conrod_example_shared/src/shapes.rs @@ -40,6 +40,7 @@ impl Gui { } } + /// Returns id of widget that the next Gui should be down_from pub fn update(&self, ui: &mut UiCell, canvas: widget::Id) -> widget::Id { use std::iter::once; @@ -104,6 +105,6 @@ impl Gui { widget::Circle::fill(40.0).right(SHAPE_GAP).align_middle_y().set(ids.circle, ui); - ids.shapes_canvas + ids.shapes_canvas // Return id of widget that the next Gui should be down_from } } From b4faf099e0761413bb8b484003733878a505ed5e Mon Sep 17 00:00:00 2001 From: Tom Daffin Date: Sat, 25 May 2019 21:09:20 -0600 Subject: [PATCH 5/8] Move number_dialer_plotpath widgets out into a separate struct --- backends/conrod_example_shared/src/lib.rs | 54 ++------------ .../src/number_dialer_plotpath.rs | 73 +++++++++++++++++++ 2 files changed, 80 insertions(+), 47 deletions(-) create mode 100644 backends/conrod_example_shared/src/number_dialer_plotpath.rs diff --git a/backends/conrod_example_shared/src/lib.rs b/backends/conrod_example_shared/src/lib.rs index dd59186df..d2d0fc063 100644 --- a/backends/conrod_example_shared/src/lib.rs +++ b/backends/conrod_example_shared/src/lib.rs @@ -16,10 +16,11 @@ extern crate rand; mod layout; mod shapes; mod button_xy_pad_toggle; +mod number_dialer_plotpath; use layout::*; -use conrod_core::{widget, Labelable, Positionable, Rect, Scalar, Sizeable, Ui, UiCell, Widget}; +use conrod_core::{widget, Positionable, Rect, Sizeable, Ui, UiCell, Widget}; pub const WIN_W: u32 = 600; pub const WIN_H: u32 = 420; @@ -77,10 +78,6 @@ widget_ids! { // Image. image_title, rust_logo, - // NumberDialer, PlotPath - dialer_title, - number_dialer, - plot_path, // Scrollbar canvas_scrollbar, } @@ -88,16 +85,18 @@ widget_ids! { pub struct Gui { ids: Ids, - button_xy_pad_toggle: button_xy_pad_toggle::Gui, shapes: shapes::Gui, + button_xy_pad_toggle: button_xy_pad_toggle::Gui, + number_dialer_plotpath: number_dialer_plotpath::Gui, } impl Gui { pub fn new(ui: &mut Ui) -> Self { Self { ids: Ids::new(ui.widget_id_generator()), - button_xy_pad_toggle: button_xy_pad_toggle::Gui::new(ui), shapes: shapes::Gui::new(ui), + button_xy_pad_toggle: button_xy_pad_toggle::Gui::new(ui), + number_dialer_plotpath: number_dialer_plotpath::Gui::new(ui), } } @@ -124,7 +123,7 @@ impl Gui { let last = self.button_xy_pad_toggle.update(ui, &mut app.button_xy_pad_toggle, ids.canvas, &rect, side); let space = rect.y.end - rect.y.start + side * 0.5 + MARGIN; - self.update_number_dialer_plotpath(ui, app, last, space); + self.number_dialer_plotpath.update(ui, &mut app.sine_frequency, ids.canvas, last, space); ///////////////////// ///// Scrollbar ///// @@ -174,43 +173,4 @@ impl Gui { .set(ids.rust_logo, ui); } - fn update_number_dialer_plotpath(&self, ui: &mut conrod_core::UiCell, app: &mut DemoApp, - last: widget::Id, space: Scalar) - { - let ids = &self.ids; - - widget::Text::new("NumberDialer and PlotPath") - .down_from(last, space) - .align_middle_x_of(ids.canvas) - .font_size(SUBTITLE_SIZE) - .set(ids.dialer_title, ui); - - // Use a `NumberDialer` widget to adjust the frequency of the sine wave below. - let min = 0.5; - let max = 200.0; - let decimal_precision = 1; - for new_freq in widget::NumberDialer::new(app.sine_frequency, min, max, decimal_precision) - .down(60.0) - .align_middle_x_of(ids.canvas) - .w_h(160.0, 40.0) - .label("F R E Q") - .set(ids.number_dialer, ui) - { - app.sine_frequency = new_freq; - } - - // Use the `PlotPath` widget to display a sine wave. - let min_x = 0.0; - let max_x = std::f32::consts::PI * 2.0 * app.sine_frequency; - let min_y = -1.0; - let max_y = 1.0; - widget::PlotPath::new(min_x, max_x, min_y, max_y, f32::sin) - .kid_area_w_of(ids.canvas) - .h(240.0) - .down(60.0) - .align_middle_x_of(ids.canvas) - .set(ids.plot_path, ui); - } - } - diff --git a/backends/conrod_example_shared/src/number_dialer_plotpath.rs b/backends/conrod_example_shared/src/number_dialer_plotpath.rs new file mode 100644 index 000000000..c050a53b8 --- /dev/null +++ b/backends/conrod_example_shared/src/number_dialer_plotpath.rs @@ -0,0 +1,73 @@ + +use conrod_core::{ + Widget, + Labelable, + Positionable, + Scalar, + Sizeable, + Ui, + UiCell, + widget, +}; + +use layout::*; + +widget_ids! { + pub struct Ids { + dialer_title, + number_dialer, + plot_path, + } +} + +pub struct Gui { + ids: Ids, +} + +impl Gui { + pub fn new(ui: &mut Ui) -> Self { + Self { + ids: Ids::new(ui.widget_id_generator()), + } + } + + /// Returns id of widget that the next Gui should be down_from + pub fn update(&self, ui: &mut UiCell, sine_frequency: &mut f32, canvas: widget::Id, last: widget::Id, space: Scalar) -> widget::Id { + let ids = &self.ids; + + widget::Text::new("NumberDialer and PlotPath") + .down_from(last, space) + .align_middle_x_of(canvas) + .font_size(SUBTITLE_SIZE) + .set(ids.dialer_title, ui); + + // Use a `NumberDialer` widget to adjust the frequency of the sine wave below. + let min = 0.5; + let max = 200.0; + let decimal_precision = 1; + for new_freq in widget::NumberDialer::new(*sine_frequency, min, max, decimal_precision) + .down(60.0) + .align_middle_x_of(canvas) + .w_h(160.0, 40.0) + .label("F R E Q") + .set(ids.number_dialer, ui) + { + *sine_frequency = new_freq; + } + + // Use the `PlotPath` widget to display a sine wave. + let min_x = 0.0; + let max_x = std::f32::consts::PI * 2.0 * *sine_frequency; + let min_y = -1.0; + let max_y = 1.0; + widget::PlotPath::new(min_x, max_x, min_y, max_y, f32::sin) + .kid_area_w_of(canvas) + .h(240.0) + .down(60.0) + .align_middle_x_of(canvas) + .set(ids.plot_path, ui); + + ids.plot_path // Return id of widget that the next Gui should be down_from + } + +} From 7dc4fb6b3677bc8452607e02039115ace02bd456 Mon Sep 17 00:00:00 2001 From: Tom Daffin Date: Sat, 25 May 2019 21:37:16 -0600 Subject: [PATCH 6/8] Move image widgets out into a separate struct --- .../src/button_xy_pad_toggle.rs | 4 +- backends/conrod_example_shared/src/image.rs | 49 +++++++++++++++++++ backends/conrod_example_shared/src/lib.rs | 38 +++++--------- 3 files changed, 62 insertions(+), 29 deletions(-) create mode 100644 backends/conrod_example_shared/src/image.rs diff --git a/backends/conrod_example_shared/src/button_xy_pad_toggle.rs b/backends/conrod_example_shared/src/button_xy_pad_toggle.rs index 36f366aa2..fb843fe51 100644 --- a/backends/conrod_example_shared/src/button_xy_pad_toggle.rs +++ b/backends/conrod_example_shared/src/button_xy_pad_toggle.rs @@ -49,11 +49,11 @@ impl Gui { } /// Returns id of widget that the next Gui should be down_from - pub fn update(&self, ui: &mut UiCell, state: &mut GuiState, canvas: widget::Id, rect: &Rect, side: f64) -> widget::Id { + pub fn update(&self, ui: &mut UiCell, state: &mut GuiState, canvas: widget::Id, last: widget::Id, rect: &Rect, side: f64) -> widget::Id { let ids = &self.ids; widget::Text::new("Button, XYPad and Toggle") - .down(60.0) + .down_from(last, 60.0) .align_middle_x_of(canvas) .font_size(SUBTITLE_SIZE) .set(ids.button_title, ui); diff --git a/backends/conrod_example_shared/src/image.rs b/backends/conrod_example_shared/src/image.rs new file mode 100644 index 000000000..0be4fe4de --- /dev/null +++ b/backends/conrod_example_shared/src/image.rs @@ -0,0 +1,49 @@ +use conrod_core::{ + Positionable, + Sizeable, + Ui, + UiCell, + Widget, + widget, +}; + +use layout::*; + +widget_ids! { + pub struct Ids { + image_title, + rust_logo, + } +} + +pub struct Gui { + ids: Ids, +} + +impl Gui { + pub fn new(ui: &mut Ui) -> Self { + Self { + ids: Ids::new(ui.widget_id_generator()), + } + } + + /// Returns id of widget that the next Gui should be down_from + pub fn update(&self, ui: &mut UiCell, rust_logo: conrod_core::image::Id, canvas: widget::Id, last: widget::Id) -> widget::Id { + let ids = &self.ids; + + widget::Text::new("Image") + .down_from(last, MARGIN) + .align_middle_x_of(canvas) + .font_size(SUBTITLE_SIZE) + .set(ids.image_title, ui); + + const LOGO_SIDE: conrod_core::Scalar = 144.0; + widget::Image::new(rust_logo) + .w_h(LOGO_SIDE, LOGO_SIDE) + .down(60.0) + .align_middle_x_of(canvas) + .set(ids.rust_logo, ui); + + ids.rust_logo // Return id of widget that the next Gui should be down_from + } +} diff --git a/backends/conrod_example_shared/src/lib.rs b/backends/conrod_example_shared/src/lib.rs index d2d0fc063..daf2cba82 100644 --- a/backends/conrod_example_shared/src/lib.rs +++ b/backends/conrod_example_shared/src/lib.rs @@ -15,6 +15,7 @@ extern crate rand; mod layout; mod shapes; +mod image; mod button_xy_pad_toggle; mod number_dialer_plotpath; @@ -75,9 +76,6 @@ widget_ids! { // The title and introduction widgets. title, introduction, - // Image. - image_title, - rust_logo, // Scrollbar canvas_scrollbar, } @@ -86,6 +84,7 @@ widget_ids! { pub struct Gui { ids: Ids, shapes: shapes::Gui, + image: image::Gui, button_xy_pad_toggle: button_xy_pad_toggle::Gui, number_dialer_plotpath: number_dialer_plotpath::Gui, } @@ -95,6 +94,7 @@ impl Gui { Self { ids: Ids::new(ui.widget_id_generator()), shapes: shapes::Gui::new(ui), + image: image::Gui::new(ui), button_xy_pad_toggle: button_xy_pad_toggle::Gui::new(ui), number_dialer_plotpath: number_dialer_plotpath::Gui::new(ui), } @@ -103,33 +103,34 @@ impl Gui { /// Instantiate a GUI demonstrating every widget available in conrod. pub fn update(&self, ui: &mut UiCell, app: &mut DemoApp) { let ids = &self.ids; + let canvas = ids.canvas; // `Canvas` is a widget that provides some basic functionality for laying out children widgets. // By default, its size is the size of the window. We'll use this as a background for the // following widgets, as well as a scrollable container for the children widgets. - widget::Canvas::new().pad(MARGIN).scroll_kids_vertically().set(ids.canvas, ui); + widget::Canvas::new().pad(MARGIN).scroll_kids_vertically().set(canvas, ui); self.update_text(ui); - let last = self.shapes.update(ui, ids.canvas); + let last = self.shapes.update(ui, canvas); - self.update_image(ui, app, last); + let last = self.image.update(ui, app.rust_logo, canvas, last); - let ball_x_range = ui.kid_area_of(ids.canvas).unwrap().w(); + let ball_x_range = ui.kid_area_of(canvas).unwrap().w(); let ball_y_range = ui.h_of(ui.window).unwrap() * 0.5; let rect = Rect::from_xy_dim([0.0, 0.0], [ball_x_range * 2.0 / 3.0, ball_y_range * 2.0 / 3.0]); let side = 130.0; - let last = self.button_xy_pad_toggle.update(ui, &mut app.button_xy_pad_toggle, ids.canvas, &rect, side); + let last = self.button_xy_pad_toggle.update(ui, &mut app.button_xy_pad_toggle, canvas, last, &rect, side); let space = rect.y.end - rect.y.start + side * 0.5 + MARGIN; - self.number_dialer_plotpath.update(ui, &mut app.sine_frequency, ids.canvas, last, space); + self.number_dialer_plotpath.update(ui, &mut app.sine_frequency, canvas, last, space); ///////////////////// ///// Scrollbar ///// ///////////////////// - widget::Scrollbar::y_axis(ids.canvas).auto_hide(true).set(ids.canvas_scrollbar, ui); + widget::Scrollbar::y_axis(canvas).auto_hide(true).set(ids.canvas_scrollbar, ui); } fn update_text(&self, ui: &mut conrod_core::UiCell){ @@ -156,21 +157,4 @@ impl Gui { .set(ids.introduction, ui); } - fn update_image(&self, ui: &mut conrod_core::UiCell, app: &mut DemoApp, last: widget::Id){ - let ids = &self.ids; - - widget::Text::new("Image") - .down_from(last, MARGIN) - .align_middle_x_of(ids.canvas) - .font_size(SUBTITLE_SIZE) - .set(ids.image_title, ui); - - const LOGO_SIDE: conrod_core::Scalar = 144.0; - widget::Image::new(app.rust_logo) - .w_h(LOGO_SIDE, LOGO_SIDE) - .down(60.0) - .align_middle_x_of(ids.canvas) - .set(ids.rust_logo, ui); - } - } From 2bbe3beb608757572a5c9c9f0e8d51745ac0759b Mon Sep 17 00:00:00 2001 From: Tom Daffin Date: Sat, 25 May 2019 21:42:43 -0600 Subject: [PATCH 7/8] Move text widgets into a separate struct --- backends/conrod_example_shared/src/lib.rs | 32 ++----------- backends/conrod_example_shared/src/text.rs | 56 ++++++++++++++++++++++ 2 files changed, 60 insertions(+), 28 deletions(-) create mode 100644 backends/conrod_example_shared/src/text.rs diff --git a/backends/conrod_example_shared/src/lib.rs b/backends/conrod_example_shared/src/lib.rs index daf2cba82..7d215b3d0 100644 --- a/backends/conrod_example_shared/src/lib.rs +++ b/backends/conrod_example_shared/src/lib.rs @@ -14,6 +14,7 @@ extern crate rand; mod layout; +mod text; mod shapes; mod image; mod button_xy_pad_toggle; @@ -73,9 +74,6 @@ widget_ids! { pub struct Ids { // The scrollable canvas. canvas, - // The title and introduction widgets. - title, - introduction, // Scrollbar canvas_scrollbar, } @@ -83,6 +81,7 @@ widget_ids! { pub struct Gui { ids: Ids, + text: text::Gui, shapes: shapes::Gui, image: image::Gui, button_xy_pad_toggle: button_xy_pad_toggle::Gui, @@ -93,6 +92,7 @@ impl Gui { pub fn new(ui: &mut Ui) -> Self { Self { ids: Ids::new(ui.widget_id_generator()), + text: text::Gui::new(ui), shapes: shapes::Gui::new(ui), image: image::Gui::new(ui), button_xy_pad_toggle: button_xy_pad_toggle::Gui::new(ui), @@ -110,7 +110,7 @@ impl Gui { // following widgets, as well as a scrollable container for the children widgets. widget::Canvas::new().pad(MARGIN).scroll_kids_vertically().set(canvas, ui); - self.update_text(ui); + self.text.update(ui, canvas); let last = self.shapes.update(ui, canvas); @@ -133,28 +133,4 @@ impl Gui { widget::Scrollbar::y_axis(canvas).auto_hide(true).set(ids.canvas_scrollbar, ui); } - fn update_text(&self, ui: &mut conrod_core::UiCell){ - let ids = &self.ids; - - // We'll demonstrate the `Text` primitive widget by using it to draw a title and an - // introduction to the example. - const TITLE: &'static str = "All Widgets"; - widget::Text::new(TITLE).font_size(TITLE_SIZE).mid_top_of(ids.canvas).set(ids.title, ui); - - const INTRODUCTION: &'static str = - "This example aims to demonstrate all widgets that are provided by conrod.\ - \n\nThe widget that you are currently looking at is the Text widget. The Text widget \ - is one of several special \"primitive\" widget types which are used to construct \ - all other widget types. These types are \"special\" in the sense that conrod knows \ - how to render them via `conrod_core::render::Primitive`s.\ - \n\nScroll down to see more widgets!"; - widget::Text::new(INTRODUCTION) - .padded_w_of(ids.canvas, MARGIN) - .down(60.0) - .align_middle_x_of(ids.canvas) - .center_justify() - .line_spacing(5.0) - .set(ids.introduction, ui); - } - } diff --git a/backends/conrod_example_shared/src/text.rs b/backends/conrod_example_shared/src/text.rs new file mode 100644 index 000000000..2d9f1137a --- /dev/null +++ b/backends/conrod_example_shared/src/text.rs @@ -0,0 +1,56 @@ +use conrod_core::{ + Positionable, + Sizeable, + Ui, + UiCell, + Widget, + widget, +}; + +use layout::*; + +widget_ids! { + pub struct Ids { + title, + introduction, + } +} + +pub struct Gui { + ids: Ids, +} + +impl Gui { + pub fn new(ui: &mut Ui) -> Self { + Self { + ids: Ids::new(ui.widget_id_generator()), + } + } + + /// Returns id of widget that the next Gui should be down_from + pub fn update(&self, ui: &mut UiCell, canvas: widget::Id) -> widget::Id { + let ids = &self.ids; + + // We'll demonstrate the `Text` primitive widget by using it to draw a title and an + // introduction to the example. + const TITLE: &'static str = "All Widgets"; + widget::Text::new(TITLE).font_size(TITLE_SIZE).mid_top_of(canvas).set(ids.title, ui); + + const INTRODUCTION: &'static str = + "This example aims to demonstrate all widgets that are provided by conrod.\ + \n\nThe widget that you are currently looking at is the Text widget. The Text widget \ + is one of several special \"primitive\" widget types which are used to construct \ + all other widget types. These types are \"special\" in the sense that conrod knows \ + how to render them via `conrod_core::render::Primitive`s.\ + \n\nScroll down to see more widgets!"; + widget::Text::new(INTRODUCTION) + .padded_w_of(canvas, MARGIN) + .down(60.0) + .align_middle_x_of(canvas) + .center_justify() + .line_spacing(5.0) + .set(ids.introduction, ui); + + ids.introduction // Return id of widget that the next Gui should be down_from + } +} From cf52e8d2246c200ec7d3421e876b04e4c0db6789 Mon Sep 17 00:00:00 2001 From: Tom Daffin Date: Sat, 25 May 2019 21:52:21 -0600 Subject: [PATCH 8/8] Final tweaks --- backends/conrod_example_shared/src/lib.rs | 10 +++++----- backends/conrod_example_shared/src/shapes.rs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backends/conrod_example_shared/src/lib.rs b/backends/conrod_example_shared/src/lib.rs index 7d215b3d0..36387e0e4 100644 --- a/backends/conrod_example_shared/src/lib.rs +++ b/backends/conrod_example_shared/src/lib.rs @@ -22,7 +22,7 @@ mod number_dialer_plotpath; use layout::*; -use conrod_core::{widget, Positionable, Rect, Sizeable, Ui, UiCell, Widget}; +use conrod_core::{widget, Rect, Ui, UiCell, Widget}; pub const WIN_W: u32 = 600; pub const WIN_H: u32 = 420; @@ -110,18 +110,18 @@ impl Gui { // following widgets, as well as a scrollable container for the children widgets. widget::Canvas::new().pad(MARGIN).scroll_kids_vertically().set(canvas, ui); - self.text.update(ui, canvas); + let mut last = self.text.update(ui, canvas); - let last = self.shapes.update(ui, canvas); + last = self.shapes.update(ui, canvas, last); - let last = self.image.update(ui, app.rust_logo, canvas, last); + last = self.image.update(ui, app.rust_logo, canvas, last); let ball_x_range = ui.kid_area_of(canvas).unwrap().w(); let ball_y_range = ui.h_of(ui.window).unwrap() * 0.5; let rect = Rect::from_xy_dim([0.0, 0.0], [ball_x_range * 2.0 / 3.0, ball_y_range * 2.0 / 3.0]); let side = 130.0; - let last = self.button_xy_pad_toggle.update(ui, &mut app.button_xy_pad_toggle, canvas, last, &rect, side); + last = self.button_xy_pad_toggle.update(ui, &mut app.button_xy_pad_toggle, canvas, last, &rect, side); let space = rect.y.end - rect.y.start + side * 0.5 + MARGIN; self.number_dialer_plotpath.update(ui, &mut app.sine_frequency, canvas, last, space); diff --git a/backends/conrod_example_shared/src/shapes.rs b/backends/conrod_example_shared/src/shapes.rs index 70b884cbe..5fd85ba77 100644 --- a/backends/conrod_example_shared/src/shapes.rs +++ b/backends/conrod_example_shared/src/shapes.rs @@ -41,13 +41,13 @@ impl Gui { } /// Returns id of widget that the next Gui should be down_from - pub fn update(&self, ui: &mut UiCell, canvas: widget::Id) -> widget::Id { + pub fn update(&self, ui: &mut UiCell, canvas: widget::Id, last: widget::Id) -> widget::Id { use std::iter::once; let ids = &self.ids; widget::Text::new("Lines and Shapes") - .down(70.0) + .down_from(last, 70.0) .align_middle_x_of(canvas) .font_size(SUBTITLE_SIZE) .set(ids.shapes_title, ui);