emilk / egui

egui: an easy-to-use immediate mode GUI in Rust that runs on both web and native
https://www.egui.rs/
Apache License 2.0
21.87k stars 1.58k forks source link

Commands not working after sending egui::ViewportCommand::Visible(false) #3655

Open BaZzz01010101 opened 10 months ago

BaZzz01010101 commented 10 months ago

Describe the bug If to hide the viewport by sending the command egui::ViewportCommand::Visible(false) the subsequent commands has no effect.

To Reproduce

fn main() {
    println!("*** Start ***");

    let shared_ctx = std::sync::Arc::new(std::sync::Mutex::new(Option::<egui::Context>::None));

    std::thread::spawn({
      let ctx = shared_ctx.clone();

      move || {
          while let None = *ctx.lock().unwrap() {
              std::thread::sleep(std::time::Duration::from_millis(100));
          }

          std::thread::sleep(std::time::Duration::from_secs(2));

          {
              let ctx = ctx.lock().unwrap().clone().unwrap();
              println!("Send command Visible(false). It works.");
              ctx.send_viewport_cmd(egui::ViewportCommand::Visible(false)); // WORKING
          }

          std::thread::sleep(std::time::Duration::from_secs(2));

          {
              let ctx = ctx.lock().unwrap().clone().unwrap();
              println!("Send command Visible(true). It doesn't work!");
              ctx.send_viewport_cmd(egui::ViewportCommand::Visible(true));  // NOT WORKING
          }

          std::thread::sleep(std::time::Duration::from_secs(2));

          {
              let ctx = ctx.lock().unwrap().clone().unwrap();
              println!("Send command Close. It doesn't work!");
              ctx.send_viewport_cmd(egui::ViewportCommand::Close);  // NOT WORKING
          }
        }
    });

    eframe::run_simple_native("Auto-Brightness", eframe::NativeOptions::default(), move |ctx, _frame| {
      {
        let mut guard = shared_ctx.lock().unwrap();

        if let None = *guard {
          *guard = Some(ctx.clone());
        }
      } // drop mutex
    }).unwrap();

    println!("*** End ***");
}

Expected behavior The main window should hide after 2 seconds from app start, then it should be displayed again and then the app should close.

Desktop (please complete the following information):

khassar00 commented 8 months ago

I had the same problem.

JB-it commented 8 months ago

I got the same issue with the Minimize and Maximize Command. Once the Window is Minimized, the Maximize command cannot open it again

I used the template that the eframe crate provides:

use eframe::egui;

fn main() {
    let native_options = eframe::NativeOptions::default();
    let _ = eframe::run_native(
        "My egui App",
        native_options,
        Box::new(|_cc| Box::new(MyEguiApp::default())),
    );
}

#[derive(Default)]
struct MyEguiApp {
    countdown: i32,
    is_minimized: bool,
}

impl eframe::App for MyEguiApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            ui.heading("Hello World!");
            ui.spinner(); //Keeps the Window refreshing and the countdown going while the window is minimized
            if ui.button("Minimize, Maximize").clicked() {

                ctx.send_viewport_cmd(egui::ViewportCommand::Minimized(true));
                self.is_minimized = true;
                self.countdown = 30;
            }

            if self.is_minimized {
                self.countdown -= 1;
                if self.countdown == 0 {
                    println!("Maximizing");
                    ctx.send_viewport_cmd(egui::ViewportCommand::Maximized(true)); //Not working
                    self.is_minimized = false; //stops the countdown
                }
            }
        });
    }
}

Expected Behavior: The code minimized the Window on the button click, and should maximize it again after 30 frames

Actual Behavior: The Window stays minimized even after sending the Command to maximize it

egui Version: 0.25.0 eframe Version: 0.25.0

khassar00 commented 8 months ago

The following text is generated by automatic translation: I spent a long time checking the code, although a lot of code is not understood, I think ViewportCommand was not processed after the window was hidden, and I modified the following code to fix the bug, but I do not know the consequences of doing so, I hope someone familiar with the internal code to confirm whether there is a problem. location : egui\crates\eframe\src\native\run.rs fn run_and_return()

            winit::event::Event::UserEvent(UserEvent::RequestRepaint {
                when,
                frame_nr,
                viewport_id,
            }) => {
                let current_frame_nr = winit_app.frame_nr(*viewport_id);
                if current_frame_nr == *frame_nr || current_frame_nr == *frame_nr + 1 {
                    log::trace!("UserEvent::RequestRepaint scheduling repaint at {when:?}");
                    if let Some(window_id) = winit_app.window_id_from_viewport_id(*viewport_id) {
                        //New code
                        winit_app.run_ui_and_paint(event_loop_window_target, window_id)
                        //Original code :EventResult::RepaintAt(window_id, *when)
                    } else {
                        EventResult::Wait
                    }
                } else {
                    log::trace!("Got outdated UserEvent::RequestRepaint");
                    EventResult::Wait // old request - we've already repainted
                }
            }
khassar00 commented 5 months ago

The following text is generated by automatic translation: I spent a long time checking the code, although a lot of code is not understood, I think ViewportCommand was not processed after the window was hidden, and I modified the following code to fix the bug, but I do not know the consequences of doing so, I hope someone familiar with the internal code to confirm whether there is a problem. location : egui\crates\eframe\src\native\run.rs fn run_and_return()

            winit::event::Event::UserEvent(UserEvent::RequestRepaint {
                when,
                frame_nr,
                viewport_id,
            }) => {
                let current_frame_nr = winit_app.frame_nr(*viewport_id);
                if current_frame_nr == *frame_nr || current_frame_nr == *frame_nr + 1 {
                    log::trace!("UserEvent::RequestRepaint scheduling repaint at {when:?}");
                    if let Some(window_id) = winit_app.window_id_from_viewport_id(*viewport_id) {
                        //New code
                        winit_app.run_ui_and_paint(event_loop_window_target, window_id)
                        //Original code :EventResult::RepaintAt(window_id, *when)
                    } else {
                        EventResult::Wait
                    }
                } else {
                    log::trace!("Got outdated UserEvent::RequestRepaint");
                    EventResult::Wait // old request - we've already repainted
                }
            }

This change caused input to freeze on the latest master branch. I reverted the changes and additionally solved the problem by exposing the winit window in egui.

 pub fn get_window_with_viewport_id(&self, viewport_id: ViewportId) -> Option<Arc<winit::window::Window>> {
        self.read(|ctx|{
           match  ctx.window_from_viewport.get(&viewport_id) {
               None => {None}
               Some(value) => {
                  Some( value.to_owned())
               }
           }
        })
    }

I think using winit::window is more flexible than ViewportCommand.

couleurm commented 5 months ago

I think using winit::window is more flexible than ViewportCommand.

How does one use get_window_with_viewport_id(), could you provide an example that integrates this with hello_world?

khassar00 commented 5 months ago

I think using winit::window is more flexible than ViewportCommand.

How does one use get_window_with_viewport_id(), could you provide an example that integrates this with hello_world?

https://github.com/khassar00/egui_fork/blob/fix/examples/fix_test/src/main.rs