How stop auto refresh of egui screen - rust

I have the following menu item
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
//let Self { label, value } = self;
// Examples of how to create different panels and windows.
// Pick whichever suits you.
// Tip: a good default choice is to just keep the `CentralPanel`.
// For inspiration and more examples, go to https://emilk.github.io/egui
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
// The top panel is often a good place for a menu bar:
egui::menu::bar(ui, |ui| {
ui.menu_button("File", |ui| {
if ui.button("Quit").clicked() {
frame.quit();
}
});
ui.menu_button("Items", |ui| {
if ui.button("Exchanges").clicked() {
println!("Exchanges");
ui.close_menu();
exchange_trans(ctx);
}
if ui.button("Coins").clicked() {
println!("Coins");
ui.close_menu();
}
if ui.button("Transactions").clicked() {
println!("Transactions");
ui.close_menu();
}
});
I call
'''
pub fn exchange_trans(ctx: &egui::Context) {
egui::SidePanel::left("side_panel").show(ctx, |ui| {
ui.heading("My egui Application");
ui.horizontal(|ui| {
ui.label("Your name: ");
ui.group(|ui| {
ui.label("Within a frame");
ui.set_min_height(200.0);
});
// ui.text_edit_singleline(&mut name);
});
}
'''
The problem is that a black screen shows up when it is available to select a menu item. When I select the Exchange menu item the screen blinks and then black to black. I think the refresh rate is set to continuous and I need it set to reactive. How do I do it or am I on the wrong track.

You don't have to disable update.
I would try to do as in the example
https://github.com/emilk/eframe_template/blob/master/src/app.rs
fn update(..) {
...
if my_variable {
egui::SidePanel::left("side_panel").show(ctx, |ui| {
ui.heading("My egui Application");
....
});
}
}
and from the menu changes my_variable to true of false - not executing the method exchange_trans(ctx); because it will be overwritten by the update
ui.menu_button("Items", |ui| {
if ui.button("Exchanges").clicked() {
println!("Exchanges");
ui.close_menu();
my_variable = !my_variable;

Related

How can I add a global keydown event listener in Dioxus)?

I'm currently trying out dioxus for rust, and I'm trying to figure out how to handle a global keyboard down event.
I want to use the arrow keys to move images back and forth:
Here's my code so far:
use dioxus::{events::*, prelude::*};
use log::{info, LevelFilter};
/**
* Specify <link data-trunk rel="copy-dir" href="src/assets" />
* in the index.html to copy the files!!
*
* You'll see them in the dist directory!
*/
fn main() {
dioxus_logger::init(LevelFilter::Info).expect("failed to init logger");
dioxus::web::launch(app);
}
fn app(cx: Scope) -> Element {
let mut index = use_state(&cx, || 1);
let change_evt = move |evt: KeyboardEvent| match evt.key.as_str() {
"ArrowRight" => index += 1,
"ArrowLeft" => index -= 1,
_ => {}
};
let url = format!("/assets/img/wallpaper/1042/0{}.jpg", index);
cx.render(rsx!(img {
src: "{url}",
onkeydown: change_evt,
}))
}
In JavaScript would've been something like
document.addEventListener('keydown', (evt) => {
// Do magic
}
I've tried following the calculator example but can't get it to work.
Any ideas?
onkeydown does not seem to work as a callback passed to an image. Wrap it in a div.
I placed an extra button there because, for some reason, the keyboard event callbacks did not register until I interacted with the app somehow (tried it in the browser).
fn app(cx: Scope) -> Element {
let mut index = use_state(&cx, || 1);
let change_evt = move |evt: KeyboardEvent| {
log::info!("{index}{}", evt.key);
match evt.key.as_str() {
"ArrowRight" => index += 1,
"ArrowLeft" => index -= 1,
_ => {}
}
};
let url = format!("/assets/img/wallpaper/1042/0{}.jpg", index);
cx.render(rsx!(
img {
src: "{url}",
}
div {
class: "display",
onkeydown: change_evt,
button {
class: "but",
onclick: move |evt| {
println!("{evt:?}");
info!("{evt:?}");
},
"Press me!"
},
},
))
}

iter_mut() doesn't run whenever I try to add status in Bevy 0.8.1

I added collision between the player and the ground, and I want to add a jumping mechanic into my game with on_ground. However, whenever I try to add status, it just stops iterating entirely.
fn collision_detection(
ground: Query<&Transform, (With<Ground>, Without<Player>)>,
mut player: Query<(&mut Transform, &mut PlayerStatus), With<Player>>,
) {
let player_size = Vec2::new(PLAYER_SIZE_X, PLAYER_SIZE_Y);
let ground_size = Vec2::new(GROUND_SIZE_X, GROUND_SIZE_Y);
for ground in ground.iter() {
for (mut player, mut status) in player.iter_mut() {
if collide(
player.translation,
player_size,
ground.translation,
ground_size,
)
.is_some()
{
status.on_ground = true;
println!("ON GROUND")
} else {
status.on_ground = false;
}
if status.on_ground {
player.translation.y += GRAVITY;
}
}
}
}
For some reason, this part wouldn't run
for (mut player, mut status) in player.iter_mut() {
if collide(
player.translation,
player_size,
ground.translation,
ground_size,
)
.is_some()
{
status.on_ground = true;
println!("ON GROUND")
} else {
status.on_ground = false;
}
if status.on_ground {
player.translation.y += GRAVITY;
}
}
It works if I only do this though:
for mut player in player.iter_mut() {
if collide(
player.translation,
player_size,
ground.translation,
ground_size,
)
.is_some()
{
player.translation.y += GRAVITY;
}
}
If you have only one player, you can use get_single_mut() instead of iter_mut() on the query.
It returns a result, so you can check in your function easily whether the player entity had been found at all. And if not send yourself some nice debugging message :)
if let Ok((mut player, mut status)) = player.get_single_mut() {
// do your collision check
} else {
// player not found in the query
}
https://docs.rs/bevy/latest/bevy/prelude/struct.Query.html#method.get_single_mut
Edit:
Looking at your comment above: if you have an already spawn entity you can always add new components to it using .insert_bundle or .insert.

custom window manager: Some GTK+ 3 windows receive focus but will not accept mouse clicks

As the title says. I'm writing a custom X11 window manager in Rust, using the xcb library. A specific window -- the "configuration" window for cairo-dock -- will not take button 1 clicks when focused, despite ungrabbing button 1 on that window.
Previously, I thought that said window was not holding focus, but that turns out to not be correct. Instead, the window in question is receiving focus, but not allowing any button 1 clicks through.
Relevant code for setting focus:
#[allow(clippy::single_match)]
fn set_focus(&mut self, window: xproto::Window) {
if window != self.root && window != self.focus {
let prev = self.focus;
// ungrab focus from the previous window
xproto::ungrab_button(
self.conn,
xproto::BUTTON_INDEX_1 as u8,
self.focus,
0
);
// make sure we don't accidentally have button 1 grabbed
xproto::ungrab_button(
self.conn,
xproto::BUTTON_INDEX_1 as u8,
window,
0
);
// See https://github.com/i3/i3/blob/b61a28f156aad545d5c54b9a6f40ef7cae1a1c9b/src/x.c#L1286-L1337
if self.needs_take_focus(window)
&& self.doesnt_take_focus(window)
&& window != base::NONE
&& window != self.root {
let client_message =
xproto::ClientMessageEvent::new(
32,
window,
self.atom("WM_PROTOCOLS"),
xproto::ClientMessageData::from_data32(
[
self.atom("WM_TAKE_FOCUS"),
self.last_timestamp,
0,
0,
0
]
)
);
xproto::send_event(self.conn, false, window, base::NONE as u32, &client_message);
} else {
debug!("{} can be focused normally", window);
xproto::set_input_focus(
self.conn,
xproto::INPUT_FOCUS_PARENT as u8,
window,
self.last_timestamp,
);
}
self.replace_prop(
self.root,
self.atom("_NET_ACTIVE_WINDOW"),
32,
&[window]
);
debug!("updating _NET_WM_STATE with _NET_WM_STATE_FOCUSED!");
self.remove_prop(prev, self.atom("_NET_WM_STATE"), self.atom("_NET_WM_STATE_FOCUSED"));
self.append_prop(window, self.atom("_NET_WM_STATE"), self.atom("_NET_WM_STATE_FOCUSED"));
self.focus = window;
debug!("focused window: {}", self.focus);
} else if window == self.root {
self.remove_prop(self.focus, self.atom("_NET_WM_STATE"), self.atom("_NET_WM_STATE_FOCUSED"));
debug!("focusing root -> NONE");
self.replace_prop(self.root, self.atom("_NET_ACTIVE_WINDOW"), 32, &[base::NONE]);
xproto::set_input_focus(self.conn, 0, base::NONE, base::CURRENT_TIME);
self.focus = xcb::NONE;
}
}
fn append_prop(&self, window: xproto::Window, prop: u32, atom: u32) {
// TODO: Check result
xproto::change_property(
self.conn,
xproto::PROP_MODE_APPEND as u8,
window,
prop,
xproto::ATOM_ATOM,
32,
&[atom]
);
}
fn remove_prop(&self, window: xproto::Window, prop: u32, atom: u32) {
let cookie = xproto::get_property(self.conn, false, window, prop, xproto::GET_PROPERTY_TYPE_ANY, 0, 4096);
match cookie.get_reply() {
Ok(res) => {
match res.value::<u32>() {
[] => {},
values => {
let mut new_values: Vec<u32> = Vec::from(values);
new_values.retain(|value| value != &atom);
self.replace_prop(window, prop, 32, &new_values);
},
}
},
Err(err) => error!("couldn't get props to remove from: {:#?}", err),
}
}
fn needs_take_focus(&self, window: xproto::Window) -> bool {
let properties_cookie =
xproto::get_property(
self.conn,
false,
window,
self.atom("WM_PROTOCOLS"),
xproto::ATOM_ANY,
0,
2048
);
match properties_cookie.get_reply() {
Ok(protocols) => {
let mut needs_help = false;
for proto in protocols.value::<u32>().iter() {
match self.atom_by_id_checked(proto) {
Some("WM_TAKE_FOCUS") => {
needs_help = true
},
_ => (),
}
}
needs_help
},
// FIXME
Err(_) => false,
}
}
fn doesnt_take_focus(&self, window: xproto::Window) -> bool {
match xcb_util::icccm::get_wm_hints(self.conn, window).get_reply() {
Ok(hints) => {
if let Some(input) = hints.input() {
input
} else {
false
}
},
// FIXME
Err(_) => false,
}
}
It turns out my problem was that I wasn't ungrabbing button 1 correctly; focus was actually being passed correctly (see question edit history), I was just forgetting to ungrab correctly because I forgot that the initial grab had a button mask on it. Thank you so much to Uli Schlachter in the comments helping me get it figured out.

Gtk Widgets returning None even when they hold data

I have a filechoosernative and a comboboxtext in my UI. Now I am trying to extract data from those two inside callbacks but they are returning me None even though they clearly have data set by the user. Why is this happening?
Excerpt from https://gitlab.com/9898287/nixwriter/-/blob/rir/src/frontend/mod.rs#L41
fn get_selected_file(&self) -> Option<std::path::PathBuf> {
let selected_file = self.fcn.get_filename();
dbg!(&selected_file);
selected_file
}
Excerpt from https://gitlab.com/9898287/nixwriter/-/blob/rir/src/frontend/mod.rs#L35
fn get_selected_device(&self) -> Option<udisks::DiskDevice> {
// Combo box text only stores a Gstring (Device ID)
// Search through the list of devices from udisks2 again
// and find the device with matching device ID
let selected_device = match self.lsblk_cbt.get_active_text() {
Some(txt) => {
dbg!(&txt);
for disk in crate::aux::backend::get_disks() {
if disk.drive.id == txt {
return Some(disk);
}
}
dbg!("No matching device found. Must reload.");
None
}
None => {
dbg!("lsblk_cbt is returning nothing");
None
}
};
dbg!(&selected_device);
selected_device
}
Both return None in https://gitlab.com/9898287/nixwriter/-/blob/rir/src/frontend/mod.rs#L110
fn set_lsblk_cbt(&mut self) {
let cbt = self.lsblk_cbt.clone();
for ddev in crate::aux::backend::get_disks() {
cbt.append_text(&ddev.drive.id);
}
let (device_chosen, file_chosen) = (
self.get_selected_device().is_some(),
self.get_selected_file().is_some(),
);
let start = self.start.clone();
cbt.connect_changed(move |_| {
start.set_sensitive(device_chosen && file_chosen);
dbg!("From set_lsblk_cbt", device_chosen, file_chosen);
});
}
even after the user has set a file and selected an item from ComboboxText.

Click on something that's not a sprite

I'm tryng to handle a click event that does not clicked on a sprite.
My first aproach would be handling normal JS events:
class EditorListener {
constructor(editor) {
...
if(window) {
window.addEventListener('click', this.onWindowClick.bind(this));
}
}
onWindowClick(event) {
if(event.target && event.target.tagName == 'CANVAS') {
Events.fire(EventType.CLICK_NOWHERE);
}
}
}
...
The problem is that this is called when I click sprites.
The goal is to simply close a dialog when I click nowhere.
Tap anywhere and run the function:
game.input.onTap.add(onTap, this);
function onTap(pointer)
{
}
Tap on these objects and run the function onDown
// enable input for some objects
yourObject1.inputEnabled = true;
yourObject2.inputEnabled = true;
yourObject1.events.onInputDown.add(onDown, this);
yourObject2.events.onInputDown.add(onDown, this);
function onDown(object, pointer)
{
// on down function
}

Resources