Skip to content

Commit 861e577

Browse files
Merge pull request #1069 from bobgates/master
Added chapter 3 to tutorial
2 parents 9a7b35b + fdc5488 commit 861e577

File tree

3 files changed

+667
-5
lines changed

3 files changed

+667
-5
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#[macro_use]
2+
extern crate conrod;
3+
extern crate find_folder;
4+
5+
use conrod::{widget, Positionable, Colorable, Widget};
6+
use conrod::backend::glium::glium::{self, Surface};
7+
8+
fn main() {
9+
10+
11+
const WIDTH: u32 = 400;
12+
const HEIGHT: u32 = 200;
13+
14+
// Build the window.
15+
let mut events_loop = glium::glutin::EventsLoop::new();
16+
let window = glium::glutin::WindowBuilder::new()
17+
.with_title("Hello Conrod")
18+
.with_dimensions(WIDTH, HEIGHT);
19+
let context = glium::glutin::ContextBuilder::new()
20+
.with_vsync(true)
21+
.with_multisampling(4);
22+
let display = glium::Display::new(window, context, &events_loop).unwrap();
23+
24+
25+
// construct our `Ui`.
26+
let mut ui = conrod::UiBuilder::new([WIDTH as f64, HEIGHT as f64]).build();
27+
28+
// Generate the widget identifiers.
29+
widget_ids!(struct Ids { text });
30+
let ids = Ids::new(ui.widget_id_generator());
31+
32+
// Add a `Font` to the `Ui`'s `font::Map` from file.
33+
let assets = find_folder::Search::KidsThenParents(3, 5)
34+
.for_folder("assets")
35+
.unwrap();
36+
let font_path = assets.join("fonts/NotoSans/NotoSans-Regular.ttf");
37+
ui.fonts.insert_from_file(font_path).unwrap();
38+
39+
// The image map describing each of our widget->image mappings (in our case, none).
40+
let image_map = conrod::image::Map::<glium::texture::Texture2d>::new();
41+
42+
// A type used for converting `conrod::render::Primitives` into `Command`s that can be used
43+
// for drawing to the glium `Surface`.
44+
let mut renderer = conrod::backend::glium::Renderer::new(&display).unwrap();
45+
46+
let mut event_loop = EventLoop::new();
47+
'main: loop {
48+
49+
let mut events = Vec::new();
50+
events_loop.poll_events(|event| events.push(event));
51+
52+
for event in event_loop.next(&mut events_loop) {
53+
54+
// Use the `winit` backend feature to convert the winit event to a conrod one.
55+
if let Some(event) = conrod::backend::winit::convert_event(event.clone(), &display) {
56+
ui.handle_event(event);
57+
event_loop.needs_update();
58+
}
59+
60+
match event {
61+
glium::glutin::Event::WindowEvent { event, .. } => {
62+
match event {
63+
glium::glutin::WindowEvent::Closed |
64+
glium::glutin::WindowEvent::KeyboardInput {
65+
input: glium::glutin::KeyboardInput {
66+
virtual_keycode: Some(glium::glutin::VirtualKeyCode::Escape), ..
67+
},
68+
..
69+
} => break 'main,
70+
_ => (),
71+
}
72+
}
73+
_ => (),
74+
}
75+
}
76+
77+
// Instantiate all widgets in the GUI.
78+
{
79+
let ui = &mut ui.set_widgets();
80+
81+
// "Hello World!" in the middle of the screen.
82+
widget::Text::new("Hello World!")
83+
.middle_of(ui.window)
84+
.color(conrod::color::WHITE)
85+
.font_size(32)
86+
.set(ids.text, ui);
87+
}
88+
89+
90+
// Render the `Ui` and then display it on the screen.
91+
if let Some(primitives) = ui.draw_if_changed() {
92+
renderer.fill(&display, primitives, &image_map);
93+
let mut target = display.draw();
94+
target.clear_color(0.0, 1.0, 0.0, 1.0);
95+
renderer.draw(&display, &mut target, &image_map).unwrap();
96+
target.finish().unwrap();
97+
}
98+
}
99+
}
100+
101+
102+
103+
104+
pub struct EventLoop {
105+
ui_needs_update: bool,
106+
last_update: std::time::Instant,
107+
}
108+
109+
impl EventLoop {
110+
pub fn new() -> Self {
111+
EventLoop {
112+
last_update: std::time::Instant::now(),
113+
ui_needs_update: true,
114+
}
115+
}
116+
117+
/// Produce an iterator yielding all available events.
118+
pub fn next(
119+
&mut self,
120+
events_loop: &mut glium::glutin::EventsLoop,
121+
) -> Vec<glium::glutin::Event> {
122+
123+
// We don't want to loop any faster than 60 FPS, so wait until it has been at least 16ms
124+
// since the last yield.
125+
let last_update = self.last_update;
126+
let sixteen_ms = std::time::Duration::from_millis(16);
127+
let duration_since_last_update = std::time::Instant::now().duration_since(last_update);
128+
if duration_since_last_update < sixteen_ms {
129+
std::thread::sleep(sixteen_ms - duration_since_last_update);
130+
}
131+
132+
// Collect all pending events.
133+
let mut events = Vec::new();
134+
events_loop.poll_events(|event| events.push(event));
135+
136+
// If there are no events and the `Ui` does not need updating, wait for the next event.
137+
if events.is_empty() && !self.ui_needs_update {
138+
events_loop.run_forever(|event| {
139+
events.push(event);
140+
glium::glutin::ControlFlow::Break
141+
});
142+
}
143+
144+
self.ui_needs_update = false;
145+
self.last_update = std::time::Instant::now();
146+
147+
events
148+
}
149+
150+
/// Notifies the event loop that the `Ui` requires another update whether or not there are any
151+
/// pending events.
152+
///
153+
/// This is primarily used on the occasion that some part of the `Ui` is still animating and
154+
/// requires further updates to do so.
155+
pub fn needs_update(&mut self) {
156+
self.ui_needs_update = true;
157+
}
158+
}

0 commit comments

Comments
 (0)