1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#[macro_use]
extern crate glium;
use std::collections::HashMap;
use glium::{Surface, Display};
use glutin::surface::WindowSurface;
use support::{ApplicationContext, State};
use glium::winit::{window::WindowId, event_loop::EventLoop};
mod support;
struct Application {
id: i32,
}
// This example shows how to dynamically open new windows.
impl ApplicationContext for Application {
const WINDOW_TITLE:&'static str = "Main Window";
fn new(_display: &Display<WindowSurface>) -> Self {
Self { id: 1 }
}
/// Here we just fill the window with a solid color based on the id so that we can easily
/// distinguish them.
fn draw_frame(&mut self, display: &Display<WindowSurface>) {
let mut frame = display.draw();
let r = if self.id & 1 == 0 { 0.0 } else { 1.0 };
let g = if self.id & 2 == 0 { 0.0 } else { 1.0 };
let b = if self.id & 4 == 0 { 0.0 } else { 1.0 };
frame.clear_color(r, g, b, 1.0);
frame.finish().unwrap()
}
}
fn main() {
let event_loop = EventLoop::builder()
.build()
.expect("event loop building");
// To simplify things we use a single type for both the main and sub windows,
// since we can easily distinguish them by their id.
let mut windows: HashMap<WindowId, State<Application>> = HashMap::new();
#[allow(deprecated)]
event_loop.run(move |event, window_target| {
match event {
// The Resumed/Suspended events are mostly for Android compatiblity since the context can get lost there at any point.
// For convenience's sake the Resumed event is also delivered on other platforms on program startup.
glium::winit::event::Event::Resumed => {
// On startup we create the main window and insert it into the HashMap just like subsequent sub windows.
let window:State<Application> = State::new(window_target, true);
windows.insert(window.window.id(), window);
},
glium::winit::event::Event::Suspended => {
windows.clear();
},
glium::winit::event::Event::WindowEvent { event, window_id, .. } => {
if let Some(state) = windows.get_mut(&window_id) {
match event {
glium::winit::event::WindowEvent::MouseInput {
state: glium::winit::event::ElementState::Released,
button: glium::winit::event::MouseButton::Left,
..
} => {
// This is the main part, where we actually create the new window, enumerate it and
// insert it into our HashMap
if state.context.id == 1 {
let mut window: State<Application> = State::new(window_target, true);
window.context.id = windows.len() as i32 + 1;
let title = format!("Window #{}", window.context.id);
window.window.set_title(&title);
windows.insert(window.window.id(), window);
} else {
windows.remove(&window_id);
}
},
glium::winit::event::WindowEvent::RedrawRequested => {
state.context.update();
state.context.draw_frame(&state.display);
}
glium::winit::event::WindowEvent::CloseRequested => {
if state.context.id == 1 {
window_target.exit();
} else {
windows.remove(&window_id);
}
},
// These two aren't necessary for this particular example, but forgetting especially the Resized
// event could lead to stretched images being rendered if you decide to render something more interesting based on this example.
glium::winit::event::WindowEvent::Resized(new_size) => {
state.display.resize(new_size.into());
},
ev => {
state.context.handle_window_event(&ev, &state.window);
},
}
}
}
_ => (),
};
})
.unwrap();
}