extern crate kiss3d; extern crate nalgebra as na; #[cfg(feature = "conrod")] use kiss3d::conrod; #[cfg(feature = "conrod")] use kiss3d::conrod::color::Color; #[cfg(feature = "conrod")] use kiss3d::conrod::position::Positionable; #[cfg(feature = "conrod")] use kiss3d::conrod::widget_ids; #[cfg(feature = "conrod")] use kiss3d::light::Light; #[cfg(feature = "conrod")] use kiss3d::window::Window; #[cfg(feature = "conrod")] use std::path::Path; #[cfg(not(feature = "conrod"))] fn main() { panic!("The 'conrod' feature must be enabled for this example to work.") } #[cfg(feature = "conrod")] fn main() { let mut window = Window::new("Kiss3d: UI"); window.set_background_color(1.0, 1.0, 1.0); let mut c = window.add_cube(0.1, 0.1, 0.1); c.set_color(1.0, 0.0, 0.0); window.set_light(Light::StickToCamera); // Generate the widget identifiers. let ids = Ids::new(window.conrod_ui_mut().widget_id_generator()); window.conrod_ui_mut().theme = theme(); window.add_texture(&Path::new("./examples/media/kitten.png"), "cat"); let cat_texture = window.conrod_texture_id("cat").unwrap(); let mut app = DemoApp::new(cat_texture); // Render loop. while window.render() { let mut ui = window.conrod_ui_mut().set_widgets(); gui(&mut ui, &ids, &mut app) } } /* * * This is he example taken from conrods' repository. * */ /// A set of reasonable stylistic defaults that works for the `gui` below. #[cfg(feature = "conrod")] pub fn theme() -> conrod::Theme { use conrod::position::{Align, Direction, Padding, Position, Relative}; conrod::Theme { name: "Demo Theme".to_string(), padding: Padding::none(), x_position: Position::Relative(Relative::Align(Align::Start), None), y_position: Position::Relative(Relative::Direction(Direction::Backwards, 20.0), None), background_color: conrod::color::DARK_CHARCOAL, shape_color: conrod::color::LIGHT_CHARCOAL, border_color: conrod::color::BLACK, border_width: 0.0, label_color: conrod::color::WHITE, font_id: None, font_size_large: 26, font_size_medium: 18, font_size_small: 12, widget_styling: conrod::theme::StyleMap::default(), mouse_drag_threshold: 0.0, double_click_threshold: std::time::Duration::from_millis(500), } } // Generate a unique `WidgetId` for each widget. #[cfg(feature = "conrod")] widget_ids! { pub struct Ids { // The scrollable canvas. canvas, // 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, cat, // Button, XyPad, Toggle. button_title, button, xy_pad, toggle, ball, // NumberDialer, PlotPath dialer_title, number_dialer, plot_path, // TextBox and TextEdit text_box, text_edit, // Scrollbar canvas_scrollbar, } } pub const WIN_W: u32 = 600; pub const WIN_H: u32 = 420; /// A demonstration of some application state we want to control with a conrod GUI. #[cfg(feature = "conrod")] pub struct DemoApp { ball_xy: conrod::Point, ball_color: conrod::Color, sine_frequency: f32, cat: conrod::image::Id, text_box: String, text_edit: String, } #[cfg(feature = "conrod")] impl DemoApp { /// Simple constructor for the `DemoApp`. pub fn new(cat: conrod::image::Id) -> Self { DemoApp { ball_xy: [0.0, 0.0], ball_color: conrod::color::WHITE, sine_frequency: 1.0, cat, text_box: "Hello".to_string(), text_edit: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n\nUt enim ad minim veniam...".to_string(), } } } /// Instantiate a GUI demonstrating every widget available in conrod. #[cfg(feature = "conrod")] pub fn gui(ui: &mut conrod::UiCell, ids: &Ids, app: &mut DemoApp) { use conrod::{widget, Colorable, Labelable, Sizeable, Widget}; use std::iter::once; const MARGIN: conrod::Scalar = 30.0; const SHAPE_GAP: conrod::Scalar = 50.0; const TITLE_SIZE: conrod::FontSize = 42; const SUBTITLE_SIZE: conrod::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) .align_right() .w(600.0) .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 some widgets that are provided by conrod.\ \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); //return; //////////////////////////// ///// 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::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::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::Scalar = 144.0; widget::Image::new(app.cat) .w_h(LOGO_SIDE, LOGO_SIDE) .down(60.0) .align_middle_x_of(ids.canvas) .set(ids.cat, ui); ///////////////////////////////// ///// Button, XYPad, Toggle ///// ///////////////////////////////// widget::Text::new("Button, XYPad and Toggle") .down_from(ids.cat, 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]; } 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]; } let is_white = app.ball_color == conrod::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::color::WHITE } else { conrod::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::color::WHITE } else { conrod::color::BLACK }; } 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; } // 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); //////////////////////////////// ///// TextBox and TextEdit ///// //////////////////////////////// for event in widget::TextBox::new(&app.text_box) .down_from(ids.plot_path, 60.0) .align_middle_x_of(ids.canvas) .padded_w_of(ids.canvas, MARGIN) .h(40.0) .set(ids.text_box, ui) { use conrod::widget::text_box::Event; match event { Event::Enter => {} Event::Update(s) => { app.text_box = s; } } } for string in widget::TextEdit::new(&app.text_edit) .down_from(ids.text_box, 60.0) .align_middle_x_of(ids.canvas) .padded_w_of(ids.canvas, MARGIN) .h(100.0) .set(ids.text_edit, ui) { app.text_edit = string; } ///////////////////// ///// Scrollbar ///// ///////////////////// widget::Scrollbar::y_axis(ids.canvas) .auto_hide(true) .set(ids.canvas_scrollbar, ui); }