Add support for text input in emilib and glium.
Add input inspectors
This commit is contained in:
parent
41eea6cd86
commit
1e685d1cb0
5 changed files with 144 additions and 50 deletions
|
@ -9,6 +9,8 @@ pub struct Context {
|
|||
/// The default style for new regions
|
||||
pub(crate) style: Mutex<Style>,
|
||||
pub(crate) fonts: Arc<Fonts>,
|
||||
/// Raw input from last frame. Use `input()` instead.
|
||||
pub(crate) last_raw_input: RawInput,
|
||||
pub(crate) input: GuiInput,
|
||||
pub(crate) memory: Mutex<Memory>,
|
||||
pub(crate) graphics: Mutex<GraphicLayers>,
|
||||
|
@ -25,7 +27,8 @@ impl Clone for Context {
|
|||
Context {
|
||||
style: Mutex::new(self.style()),
|
||||
fonts: self.fonts.clone(),
|
||||
input: self.input,
|
||||
last_raw_input: self.last_raw_input.clone(),
|
||||
input: self.input.clone(),
|
||||
memory: Mutex::new(self.memory.lock().clone()),
|
||||
graphics: Mutex::new(self.graphics.lock().clone()),
|
||||
output: Mutex::new(self.output.lock().clone()),
|
||||
|
@ -39,6 +42,7 @@ impl Context {
|
|||
Context {
|
||||
style: Default::default(),
|
||||
fonts: Arc::new(Fonts::new(pixels_per_point)),
|
||||
last_raw_input: Default::default(),
|
||||
input: Default::default(),
|
||||
memory: Default::default(),
|
||||
graphics: Default::default(),
|
||||
|
@ -52,6 +56,11 @@ impl Context {
|
|||
(point * self.input.pixels_per_point).round() / self.input.pixels_per_point
|
||||
}
|
||||
|
||||
/// Raw input from last frame. Use `input()` instead.
|
||||
pub fn last_raw_input(&self) -> &RawInput {
|
||||
&self.last_raw_input
|
||||
}
|
||||
|
||||
pub fn input(&self) -> &GuiInput {
|
||||
&self.input
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::{mesher::*, widgets::*, *};
|
||||
use crate::{containers::*, mesher::*, widgets::*, *};
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
struct Stats {
|
||||
|
@ -38,10 +38,12 @@ impl Emigui {
|
|||
}
|
||||
|
||||
let gui_input = GuiInput::from_last_and_new(&self.last_input, &new_input);
|
||||
self.last_input = new_input;
|
||||
self.last_input = new_input.clone(); // TODO: also stored in Context. Remove this one
|
||||
|
||||
// TODO: avoid this clone
|
||||
let mut new_ctx = (*self.ctx).clone();
|
||||
|
||||
new_ctx.last_raw_input = new_input;
|
||||
new_ctx.begin_frame(gui_input);
|
||||
self.ctx = Arc::new(new_ctx);
|
||||
}
|
||||
|
@ -100,6 +102,17 @@ impl Emigui {
|
|||
}
|
||||
});
|
||||
|
||||
region.collapsing("Input", |region| {
|
||||
CollapsingHeader::new("Raw Input")
|
||||
.default_open()
|
||||
.show(region, |region| {
|
||||
region.ctx().last_raw_input().clone().ui(region)
|
||||
});
|
||||
CollapsingHeader::new("Input")
|
||||
.default_open()
|
||||
.show(region, |region| region.input().clone().ui(region));
|
||||
});
|
||||
|
||||
region.collapsing("Stats", |region| {
|
||||
region.add(label!(
|
||||
"Screen size: {} x {} points, pixels_per_point: {}",
|
||||
|
@ -132,3 +145,35 @@ fn font_definitions_ui(font_definitions: &mut FontDefinitions, region: &mut Regi
|
|||
*font_definitions = crate::fonts::default_font_definitions();
|
||||
}
|
||||
}
|
||||
|
||||
impl RawInput {
|
||||
pub fn ui(&self, region: &mut Region) {
|
||||
// TODO: simpler way to show values, e.g. `region.value("Mouse Pos:", self.mouse_pos);
|
||||
region.add(label!("mouse_down: {}", self.mouse_down));
|
||||
region.add(label!("mouse_pos: {:.1?}", self.mouse_pos));
|
||||
region.add(label!("scroll_delta: {:?}", self.scroll_delta));
|
||||
region.add(label!("screen_size: {:?}", self.screen_size));
|
||||
region.add(label!("pixels_per_point: {}", self.pixels_per_point));
|
||||
region.add(label!("time: {:.3} s", self.time));
|
||||
region.add(label!("text: {:?}", self.text));
|
||||
// region.add(label!("dropped_files: {}", self.dropped_files));
|
||||
// region.add(label!("hovered_files: {}", self.hovered_files));
|
||||
}
|
||||
}
|
||||
|
||||
impl GuiInput {
|
||||
pub fn ui(&self, region: &mut Region) {
|
||||
region.add(label!("mouse_down: {}", self.mouse_down));
|
||||
region.add(label!("mouse_pressed: {}", self.mouse_pressed));
|
||||
region.add(label!("mouse_released: {}", self.mouse_released));
|
||||
region.add(label!("mouse_pos: {:?}", self.mouse_pos));
|
||||
region.add(label!("mouse_move: {:?}", self.mouse_move));
|
||||
region.add(label!("scroll_delta: {:?}", self.scroll_delta));
|
||||
region.add(label!("screen_size: {:?}", self.screen_size));
|
||||
region.add(label!("pixels_per_point: {}", self.pixels_per_point));
|
||||
region.add(label!("time: {}", self.time));
|
||||
region.add(label!("text: {:?}", self.text));
|
||||
// region.add(label!("dropped_files: {}", self.dropped_files));
|
||||
// region.add(label!("hovered_files: {}", self.hovered_files));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
|||
|
||||
/// What the integration gives to the gui.
|
||||
/// All coordinates in emigui is in point/logical coordinates.
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct RawInput {
|
||||
/// Is the button currently down?
|
||||
|
@ -29,10 +29,19 @@ pub struct RawInput {
|
|||
|
||||
/// Time in seconds. Relative to whatever. Used for animation.
|
||||
pub time: f64,
|
||||
|
||||
/// Text input, e.g. via keyboard or paste action
|
||||
pub text: String,
|
||||
|
||||
/// Files has been dropped into the window.
|
||||
pub dropped_files: Vec<std::path::PathBuf>,
|
||||
|
||||
/// Someone is threatening to drop these on us.
|
||||
pub hovered_files: Vec<std::path::PathBuf>,
|
||||
}
|
||||
|
||||
/// What the gui maintains
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct GuiInput {
|
||||
/// Is the button currently down?
|
||||
/// true the frame when it is pressed,
|
||||
|
@ -63,6 +72,15 @@ pub struct GuiInput {
|
|||
|
||||
/// Time in seconds. Relative to whatever. Used for animation.
|
||||
pub time: f64,
|
||||
|
||||
/// Text input, e.g. via keyboard or paste action
|
||||
pub text: String,
|
||||
|
||||
/// Files has been dropped into the window.
|
||||
pub dropped_files: Vec<std::path::PathBuf>,
|
||||
|
||||
/// Someone is threatening to drop these on us.
|
||||
pub hovered_files: Vec<std::path::PathBuf>,
|
||||
}
|
||||
|
||||
impl GuiInput {
|
||||
|
@ -81,6 +99,9 @@ impl GuiInput {
|
|||
screen_size: new.screen_size,
|
||||
pixels_per_point: new.pixels_per_point,
|
||||
time: new.time,
|
||||
text: new.text.clone(),
|
||||
dropped_files: new.dropped_files.clone(),
|
||||
hovered_files: new.hovered_files.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ fn main() {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let mut quit = false;
|
||||
let mut running = true;
|
||||
|
||||
// used to keep track of time for animations
|
||||
let start_time = Instant::now();
|
||||
|
@ -45,7 +45,7 @@ fn main() {
|
|||
|
||||
let mut example_app = ExampleApp::default();
|
||||
|
||||
while !quit {
|
||||
while running {
|
||||
{
|
||||
// Keep smooth frame rate. TODO: proper vsync
|
||||
let frame_duration = frame_start.elapsed();
|
||||
|
@ -55,54 +55,22 @@ fn main() {
|
|||
frame_start = Instant::now();
|
||||
}
|
||||
|
||||
{
|
||||
raw_input.time = start_time.elapsed().as_nanos() as f64 * 1e-9;
|
||||
raw_input.scroll_delta = vec2(0.0, 0.0);
|
||||
raw_input.text.clear();
|
||||
raw_input.dropped_files.clear();
|
||||
raw_input.hovered_files.clear();
|
||||
events_loop.poll_events(|event| input_event(event, &mut raw_input, &mut running));
|
||||
}
|
||||
|
||||
events_loop.poll_events(|event| match event {
|
||||
glutin::Event::WindowEvent { event, .. } => match event {
|
||||
glutin::WindowEvent::CloseRequested => quit = true,
|
||||
|
||||
glutin::WindowEvent::Resized(glutin::dpi::LogicalSize { width, height }) => {
|
||||
raw_input.screen_size = vec2(width as f32, height as f32);
|
||||
}
|
||||
glutin::WindowEvent::MouseInput { state, .. } => {
|
||||
raw_input.mouse_down = state == glutin::ElementState::Pressed;
|
||||
}
|
||||
glutin::WindowEvent::CursorMoved { position, .. } => {
|
||||
raw_input.mouse_pos = Some(pos2(position.x as f32, position.y as f32));
|
||||
}
|
||||
glutin::WindowEvent::KeyboardInput { input, .. } => {
|
||||
if input.virtual_keycode == Some(glutin::VirtualKeyCode::Q)
|
||||
&& input.modifiers.logo
|
||||
{
|
||||
quit = true;
|
||||
}
|
||||
}
|
||||
glutin::WindowEvent::MouseWheel { delta, .. } => {
|
||||
match delta {
|
||||
glutin::MouseScrollDelta::LineDelta(x, y) => {
|
||||
raw_input.scroll_delta = vec2(x, y) * 24.0;
|
||||
}
|
||||
glutin::MouseScrollDelta::PixelDelta(delta) => {
|
||||
// Actually point delta
|
||||
raw_input.scroll_delta = vec2(delta.x as f32, delta.y as f32);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// dbg!(event);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
});
|
||||
|
||||
emigui.begin_frame(raw_input);
|
||||
emigui.begin_frame(raw_input.clone()); // TODO: avoid clone
|
||||
let mut region = emigui.background_region();
|
||||
let mut region = region.centered_column(region.available_width().min(480.0));
|
||||
region.set_align(Align::Min);
|
||||
region.add(label!("Emigui running inside of Glium").text_style(emigui::TextStyle::Heading));
|
||||
if region.add(Button::new("Quit")).clicked {
|
||||
quit = true;
|
||||
running = false;
|
||||
}
|
||||
|
||||
// TODO: Make it even simpler to show a window
|
||||
|
@ -139,3 +107,53 @@ fn main() {
|
|||
display.gl_window().set_cursor(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
fn input_event(event: glutin::Event, raw_input: &mut RawInput, running: &mut bool) {
|
||||
use glutin::WindowEvent::*;
|
||||
match event {
|
||||
glutin::Event::WindowEvent { event, .. } => match event {
|
||||
CloseRequested | Destroyed => *running = false,
|
||||
|
||||
DroppedFile(path) => raw_input.dropped_files.push(path),
|
||||
HoveredFile(path) => raw_input.hovered_files.push(path),
|
||||
|
||||
Resized(glutin::dpi::LogicalSize { width, height }) => {
|
||||
raw_input.screen_size = vec2(width as f32, height as f32);
|
||||
}
|
||||
MouseInput { state, .. } => {
|
||||
raw_input.mouse_down = state == glutin::ElementState::Pressed;
|
||||
}
|
||||
CursorMoved { position, .. } => {
|
||||
raw_input.mouse_pos = Some(pos2(position.x as f32, position.y as f32));
|
||||
}
|
||||
CursorLeft { .. } => {
|
||||
raw_input.mouse_pos = None;
|
||||
}
|
||||
ReceivedCharacter(ch) => {
|
||||
raw_input.text.push(ch);
|
||||
}
|
||||
KeyboardInput { input, .. } => {
|
||||
if input.virtual_keycode == Some(glutin::VirtualKeyCode::Q) && input.modifiers.logo
|
||||
{
|
||||
*running = false;
|
||||
}
|
||||
}
|
||||
MouseWheel { delta, .. } => {
|
||||
match delta {
|
||||
glutin::MouseScrollDelta::LineDelta(x, y) => {
|
||||
raw_input.scroll_delta = vec2(x, y) * 24.0;
|
||||
}
|
||||
glutin::MouseScrollDelta::PixelDelta(delta) => {
|
||||
// Actually point delta
|
||||
raw_input.scroll_delta = vec2(delta.x as f32, delta.y as f32);
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: HiDpiFactorChanged
|
||||
_ => {
|
||||
// dbg!(event);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ impl State {
|
|||
fn run(&mut self, raw_input: RawInput) -> Result<Output, JsValue> {
|
||||
let everything_start = now_sec();
|
||||
|
||||
let pixels_per_point = raw_input.pixels_per_point;
|
||||
self.emigui.begin_frame(raw_input);
|
||||
|
||||
let mut region = self.emigui.background_region();
|
||||
|
@ -98,7 +99,7 @@ impl State {
|
|||
bg_color,
|
||||
batches,
|
||||
self.emigui.texture(),
|
||||
raw_input.pixels_per_point,
|
||||
pixels_per_point,
|
||||
)?;
|
||||
|
||||
self.frame_times.push_back(now_sec() - everything_start);
|
||||
|
|
Loading…
Reference in a new issue