Skip to content

Commit 73b6fad

Browse files
authored
Add globals and callback handling (#120)
1 parent 56736ea commit 73b6fad

16 files changed

Lines changed: 675 additions & 80 deletions

File tree

crates/processing_input/src/lib.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,3 +295,47 @@ pub fn input_key() -> error::Result<Option<char>> {
295295
pub fn input_key_code() -> error::Result<Option<KeyCode>> {
296296
app_mut(|app| Ok(app.world().resource::<LastKey>().code))
297297
}
298+
299+
pub fn input_mouse_any_just_pressed() -> error::Result<bool> {
300+
app_mut(|app| {
301+
Ok(app
302+
.world()
303+
.resource::<ButtonInput<MouseButton>>()
304+
.get_just_pressed()
305+
.next()
306+
.is_some())
307+
})
308+
}
309+
310+
pub fn input_mouse_any_just_released() -> error::Result<bool> {
311+
app_mut(|app| {
312+
Ok(app
313+
.world()
314+
.resource::<ButtonInput<MouseButton>>()
315+
.get_just_released()
316+
.next()
317+
.is_some())
318+
})
319+
}
320+
321+
pub fn input_key_any_just_pressed() -> error::Result<bool> {
322+
app_mut(|app| Ok(app.world().resource::<LastKey>().just_pressed))
323+
}
324+
325+
pub fn input_key_any_just_released() -> error::Result<bool> {
326+
app_mut(|app| Ok(app.world().resource::<LastKey>().just_released))
327+
}
328+
329+
pub fn input_mouse_moved() -> error::Result<bool> {
330+
app_mut(|app| {
331+
let d = app.world().resource::<AccumulatedMouseMotion>().delta;
332+
Ok(d.x != 0.0 || d.y != 0.0)
333+
})
334+
}
335+
336+
pub fn input_mouse_scrolled() -> error::Result<bool> {
337+
app_mut(|app| {
338+
let d = app.world().resource::<AccumulatedMouseScroll>().delta;
339+
Ok(d.x != 0.0 || d.y != 0.0)
340+
})
341+
}

crates/processing_input/src/state.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ impl CursorPosition {
2626
pub struct LastKey {
2727
pub code: Option<KeyCode>,
2828
pub character: Option<char>,
29+
pub just_pressed: bool,
30+
pub just_released: bool,
2931
}
3032

3133
#[derive(Resource, Default)]
@@ -51,13 +53,21 @@ pub fn track_cursor_position(
5153
}
5254

5355
pub fn track_last_key(mut reader: MessageReader<KeyboardInput>, mut last: ResMut<LastKey>) {
54-
if let Some(event) = reader
55-
.read()
56-
.filter(|e| e.state == ButtonState::Pressed)
57-
.last()
58-
{
59-
last.code = Some(event.key_code);
60-
last.character = event.text.as_ref().and_then(|t| t.chars().next());
56+
// our cbs fire on key auto repeats but bevy just_pressed only fires on the initial press
57+
// we track edge state off of the raw input stream
58+
last.just_pressed = false;
59+
last.just_released = false;
60+
for event in reader.read() {
61+
match event.state {
62+
ButtonState::Pressed => {
63+
last.code = Some(event.key_code);
64+
last.character = event.text.as_ref().and_then(|t| t.chars().next());
65+
last.just_pressed = true;
66+
}
67+
ButtonState::Released => {
68+
last.just_released = true;
69+
}
70+
}
6171
}
6272
}
6373

crates/processing_pyo3/mewnala/__init__.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,66 @@
99
_sub = getattr(_native, _name, None)
1010
if _sub is not None:
1111
_sys.modules[f"{__name__}.{_name}"] = _sub
12-
del _sys, _native, _name, _sub
12+
13+
# global var handling. for wildcard import of our module, we copy into globals, otherwise
14+
# we dispatch to get attr and call the underlying getter method
15+
16+
_DYNAMIC_GRAPHICS_ATTRS = (
17+
"width",
18+
"height",
19+
"focused",
20+
"pixel_width",
21+
"pixel_height",
22+
"pixel_density",
23+
)
24+
_DYNAMIC_FUNCTIONS = (
25+
"mouse_x",
26+
"mouse_y",
27+
"pmouse_x",
28+
"pmouse_y",
29+
"frame_count",
30+
"delta_time",
31+
"elapsed_time",
32+
)
33+
_DYNAMIC = (
34+
_DYNAMIC_GRAPHICS_ATTRS + _DYNAMIC_FUNCTIONS + (
35+
"mouse_is_pressed",
36+
"mouse_button",
37+
"moved_x",
38+
"moved_y",
39+
"mouse_wheel",
40+
"key",
41+
"key_code",
42+
"key_is_pressed",
43+
"display_width",
44+
"display_height",
45+
)
46+
)
47+
48+
49+
def _get_graphics():
50+
return getattr(_native, "_graphics", None)
51+
52+
53+
def __getattr__(name):
54+
if name in _DYNAMIC_GRAPHICS_ATTRS:
55+
g = _get_graphics()
56+
if g is not None:
57+
return getattr(g, name)
58+
if name in _DYNAMIC_FUNCTIONS:
59+
fn = getattr(_native, name, None)
60+
if callable(fn):
61+
return fn()
62+
if name in ("display_width", "display_height"):
63+
mon = getattr(_native, "primary_monitor", lambda: None)()
64+
if mon is None:
65+
return 0
66+
return mon.width if name == "display_width" else mon.height
67+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
68+
69+
70+
def __dir__():
71+
return sorted(set(list(globals().keys()) + list(_DYNAMIC)))
72+
73+
74+
del _sys, _name, _sub

crates/processing_pyo3/src/graphics.rs

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -132,40 +132,7 @@ impl PyBlendMode {
132132
const OP_MAX: u8 = 4;
133133
}
134134

135-
#[pyclass(unsendable)]
136-
pub struct Surface {
137-
pub(crate) entity: Entity,
138-
glfw_ctx: Option<GlfwContext>,
139-
}
140-
141-
#[pymethods]
142-
impl Surface {
143-
pub fn poll_events(&mut self) -> bool {
144-
match &mut self.glfw_ctx {
145-
Some(ctx) => ctx.poll_events(),
146-
None => true, // no-op, offscreen surfaces never close
147-
}
148-
}
149-
150-
#[getter]
151-
pub fn display_density(&self) -> PyResult<f32> {
152-
match &self.glfw_ctx {
153-
Some(ctx) => Ok(ctx.content_scale()),
154-
None => Ok(1.0),
155-
}
156-
}
157-
158-
pub fn set_pixel_density(&self, density: f32) -> PyResult<()> {
159-
surface_set_pixel_density(self.entity, density)
160-
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
161-
}
162-
}
163-
164-
impl Drop for Surface {
165-
fn drop(&mut self) {
166-
let _ = surface_destroy(self.entity);
167-
}
168-
}
135+
pub use crate::surface::Surface;
169136

170137
#[pyclass]
171138
#[derive(Debug)]
@@ -318,6 +285,10 @@ impl Geometry {
318285
pub struct Graphics {
319286
pub(crate) entity: Entity,
320287
pub surface: Surface,
288+
#[pyo3(get)]
289+
pub width: u32,
290+
#[pyo3(get)]
291+
pub height: u32,
321292
}
322293

323294
impl Drop for Graphics {
@@ -364,6 +335,8 @@ impl Graphics {
364335
Ok(Self {
365336
entity: graphics,
366337
surface,
338+
width,
339+
height,
367340
})
368341
}
369342

@@ -399,9 +372,31 @@ impl Graphics {
399372
Ok(Self {
400373
entity: graphics,
401374
surface,
375+
width,
376+
height,
402377
})
403378
}
404379

380+
#[getter]
381+
pub fn focused(&self) -> PyResult<bool> {
382+
self.surface.focused()
383+
}
384+
385+
#[getter]
386+
pub fn pixel_density(&self) -> PyResult<f32> {
387+
self.surface.pixel_density()
388+
}
389+
390+
#[getter]
391+
pub fn pixel_width(&self) -> PyResult<u32> {
392+
self.surface.pixel_width()
393+
}
394+
395+
#[getter]
396+
pub fn pixel_height(&self) -> PyResult<u32> {
397+
self.surface.pixel_height()
398+
}
399+
405400
pub fn readback_png(&self) -> PyResult<Vec<u8>> {
406401
let raw = graphics_readback_raw(self.entity)
407402
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;

crates/processing_pyo3/src/input.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -80,20 +80,20 @@ pub fn key_code() -> PyResult<Option<u32>> {
8080
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))
8181
}
8282

83-
pub fn sync_globals(func: &Bound<'_, PyAny>, surface: Entity) -> PyResult<()> {
84-
let globals = func.getattr("__globals__")?;
85-
globals.set_item("mouse_x", mouse_x(surface)?)?;
86-
globals.set_item("mouse_y", mouse_y(surface)?)?;
87-
globals.set_item("pmouse_x", pmouse_x(surface)?)?;
88-
globals.set_item("pmouse_y", pmouse_y(surface)?)?;
89-
globals.set_item("mouse_is_pressed", mouse_is_pressed()?)?;
90-
globals.set_item("mouse_button", mouse_button()?)?;
91-
globals.set_item("moved_x", moved_x()?)?;
92-
globals.set_item("moved_y", moved_y()?)?;
93-
globals.set_item("mouse_wheel", mouse_wheel()?)?;
94-
globals.set_item("key", key()?)?;
95-
globals.set_item("key_code", key_code()?)?;
96-
globals.set_item("key_is_pressed", key_is_pressed()?)?;
83+
pub fn sync_globals(globals: &Bound<'_, PyAny>, surface: Entity) -> PyResult<()> {
84+
use crate::set_tracked;
85+
set_tracked(globals, "mouse_x", mouse_x(surface)?)?;
86+
set_tracked(globals, "mouse_y", mouse_y(surface)?)?;
87+
set_tracked(globals, "pmouse_x", pmouse_x(surface)?)?;
88+
set_tracked(globals, "pmouse_y", pmouse_y(surface)?)?;
89+
set_tracked(globals, "mouse_is_pressed", mouse_is_pressed()?)?;
90+
set_tracked(globals, "mouse_button", mouse_button()?)?;
91+
set_tracked(globals, "moved_x", moved_x()?)?;
92+
set_tracked(globals, "moved_y", moved_y()?)?;
93+
set_tracked(globals, "mouse_wheel", mouse_wheel()?)?;
94+
set_tracked(globals, "key", key()?)?;
95+
set_tracked(globals, "key_code", key_code()?)?;
96+
set_tracked(globals, "key_is_pressed", key_is_pressed()?)?;
9797
Ok(())
9898
}
9999

0 commit comments

Comments
 (0)