[GH-ISSUE #45] Better GUI #5

Closed
opened 2026-03-03 13:44:55 +03:00 by kerem · 9 comments
Owner

Originally created by @loganmc10 on GitHub (Jan 31, 2024).
Original GitHub issue: https://github.com/gopher64/gopher64/issues/45

Originally assigned to: @loganmc10 on GitHub.

Originally created by @loganmc10 on GitHub (Jan 31, 2024). Original GitHub issue: https://github.com/gopher64/gopher64/issues/45 Originally assigned to: @loganmc10 on GitHub.
kerem closed this issue 2026-03-03 13:44:55 +03:00
Author
Owner

@DarthSidious666 commented on GitHub (Oct 18, 2024):

I've managed to clone the Simple64 UI using e-gui, I'm not sure which parts I would need to edit in your file so please adapt the code to fit.

use eframe::egui;

fn main() -> eframe::Result {
    let options = eframe::NativeOptions 
    {
        viewport: egui::ViewportBuilder::default()
            .with_inner_size([1024.0, 768.0]),
        ..Default::default()
    };
    let _ = eframe::run_native(
        "Simple64: ",
        options,
        Box::new(|_cc| Ok(Box::<Simple64Gui>::default())),
    );
    Ok(())
}

#[derive(Default)]
struct Simple64Gui
{

}

impl eframe::App for Simple64Gui {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) 
    {
        egui::CentralPanel::default().show(ctx, |ui| 
            {
                egui::menu::bar(ui, |ui|
                {
                    ui.set_max_width(300.0);
                    ui.menu_button("File", |ui|
                    {
                        if ui.button("Open ROM").clicked()
                        {

                        }

                        ui.menu_button("Recent", |ui|
                        {
                            
                        });
                        
                        ui.horizontal(|ui| {} );
    
                        if ui.button("Save State").clicked()
                        {

                        }

                        if ui.button("Load State").clicked()
                        {

                        }
        
                        ui.menu_button("Change Save Slot", |ui|
                        {
                            if ui.button("Slot 0").clicked()
                            {

                            }
                            
                            if ui.button("Slot 1").clicked()
                            {
                                
                            }
                            
                            if ui.button("Slot 2").clicked()
                            {
                                
                            }
                            
                            if ui.button("Slot 3").clicked()
                            {
                                
                            }
                            
                            if ui.button("Slot 4").clicked()
                            {
                                
                            }
                            
                            if ui.button("Slot 5").clicked()
                            {
                                
                            }
                            
                            if ui.button("Slot 6").clicked()
                            {
                                
                            }
                            
                            if ui.button("Slot 7").clicked()
                            {
                                
                            }
                            
                            if ui.button("Slot 8").clicked()
                            {
                                
                            }

                            if ui.button("Slot 9").clicked()
                            {
                                
                            }
                        });
        
                        ui.horizontal(|ui| {} );
    
                        if ui.button("Save State To...").clicked()
                        {

                        }

                        if ui.button("Load State From...").clicked()
                        {

                        }
    
                        ui.horizontal(|ui| {} );
    
                        ui.menu_button("Gameboy Cartridges", |ui|
                        {
                            if ui.button("Player 1 SAV").clicked()
                            {

                            }

                            if ui.button("Player 1 ROM").clicked()
                            {

                            }

                            if ui.button("Clear Player 1").clicked()
                            {

                            }

                            ui.horizontal(|ui| {} );

                            if ui.button("Player 2 SAV").clicked()
                            {

                            }

                            if ui.button("Player 2 ROM").clicked()
                            {

                            }

                            if ui.button("Clear Player 2").clicked()
                            {

                            }

                            ui.horizontal(|ui| {} );

                            if ui.button("Player 3 SAV").clicked()
                            {

                            }
                            
                            if ui.button("Player 3 ROM").clicked()
                            {

                            }
                            
                            if ui.button("Clear Player 3").clicked()
                            {

                            }

                            ui.horizontal(|ui| {} );

                            if ui.button("Player 4 SAV").clicked()
                            {

                            }

                            if ui.button("Player 4 ROM").clicked()
                            {

                            }

                            if ui.button("Clear Player 4").clicked()
                            {

                            }

                            ui.horizontal(|ui| {} );
                        });
    
                        if ui.button("Take Snapshot").clicked()
                        {

                        }
    
                        ui.horizontal(|ui| {} );
                        
                        if ui.button("Exit").clicked()
                        {

                        }
    
                    });

                    ui.vertical(|ui| {} );

                    ui.menu_button("Emulation", |ui|
                    {
                        if ui.button("Toggle Fullscreen (Alt + Enter)").clicked()
                        {

                        }

                        if ui.button("Cheats").clicked()
                        {

                        }

                        ui.horizontal(|ui| {} );

                        let mut volume: f32 = 100.0;

                        ui.add(egui::Slider::new(&mut volume, 0.0..=100.0).text("Volume:"));

                        if ui.button("Mute / Unmute").clicked()
                        {

                        }

                        ui.horizontal(|ui| {} );

                        if ui.button("Pause / Unpause Game").clicked()
                        {

                        }

                        if ui.button("Stop Emulator").clicked()
                        {

                        }

                        if ui.button("Hard Reset").clicked()
                        {

                        }

                        if ui.button("Soft Reset").clicked()
                        {

                        }

                        if ui.button("Toggle Speed Limiter").clicked()
                        {

                        }

                        ui.horizontal(|ui| {} );

                        if ui.button("View Log").clicked()
                        {

                        }
                    });

                    ui.vertical(|ui| {} );

                    ui.menu_button("Settings", |ui|
                    {
                        if ui.button("Input Plugin and Config Path Selection").clicked()
                        {

                        }

                        if ui.button("Emulator Core and Video Settings").clicked()
                        {

                        }

                        if ui.button("Controller Setup").clicked()
                        {

                        }

                        if ui.button("Hotkey Setup").clicked()
                        {

                        }
                    });

                    ui.vertical(|ui| {} );
                    
                    ui.menu_button("NetPlay", |ui| 
                    {
                        if ui.button("Create Room").clicked()
                        {

                        }

                        if ui.button("Join Room").clicked()
                        {

                        }
                    });

                    ui.vertical(|ui| {} );

                    ui.menu_button("Community", |ui|
                    {
                        if ui.button("Join Discord Server").clicked()
                        {

                        }

                        if ui.button("Support on Patreon").clicked()
                        {

                        }

                        if ui.button("Support on GitHub").clicked()
                        {

                        }
                    });
                });
            });
    }
}

image
image
image
image
image
image
image
image

<!-- gh-comment-id:2423070884 --> @DarthSidious666 commented on GitHub (Oct 18, 2024): I've managed to clone the Simple64 UI using e-gui, I'm not sure which parts I would need to edit in your file so please adapt the code to fit. ``` use eframe::egui; fn main() -> eframe::Result { let options = eframe::NativeOptions { viewport: egui::ViewportBuilder::default() .with_inner_size([1024.0, 768.0]), ..Default::default() }; let _ = eframe::run_native( "Simple64: ", options, Box::new(|_cc| Ok(Box::<Simple64Gui>::default())), ); Ok(()) } #[derive(Default)] struct Simple64Gui { } impl eframe::App for Simple64Gui { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { egui::CentralPanel::default().show(ctx, |ui| { egui::menu::bar(ui, |ui| { ui.set_max_width(300.0); ui.menu_button("File", |ui| { if ui.button("Open ROM").clicked() { } ui.menu_button("Recent", |ui| { }); ui.horizontal(|ui| {} ); if ui.button("Save State").clicked() { } if ui.button("Load State").clicked() { } ui.menu_button("Change Save Slot", |ui| { if ui.button("Slot 0").clicked() { } if ui.button("Slot 1").clicked() { } if ui.button("Slot 2").clicked() { } if ui.button("Slot 3").clicked() { } if ui.button("Slot 4").clicked() { } if ui.button("Slot 5").clicked() { } if ui.button("Slot 6").clicked() { } if ui.button("Slot 7").clicked() { } if ui.button("Slot 8").clicked() { } if ui.button("Slot 9").clicked() { } }); ui.horizontal(|ui| {} ); if ui.button("Save State To...").clicked() { } if ui.button("Load State From...").clicked() { } ui.horizontal(|ui| {} ); ui.menu_button("Gameboy Cartridges", |ui| { if ui.button("Player 1 SAV").clicked() { } if ui.button("Player 1 ROM").clicked() { } if ui.button("Clear Player 1").clicked() { } ui.horizontal(|ui| {} ); if ui.button("Player 2 SAV").clicked() { } if ui.button("Player 2 ROM").clicked() { } if ui.button("Clear Player 2").clicked() { } ui.horizontal(|ui| {} ); if ui.button("Player 3 SAV").clicked() { } if ui.button("Player 3 ROM").clicked() { } if ui.button("Clear Player 3").clicked() { } ui.horizontal(|ui| {} ); if ui.button("Player 4 SAV").clicked() { } if ui.button("Player 4 ROM").clicked() { } if ui.button("Clear Player 4").clicked() { } ui.horizontal(|ui| {} ); }); if ui.button("Take Snapshot").clicked() { } ui.horizontal(|ui| {} ); if ui.button("Exit").clicked() { } }); ui.vertical(|ui| {} ); ui.menu_button("Emulation", |ui| { if ui.button("Toggle Fullscreen (Alt + Enter)").clicked() { } if ui.button("Cheats").clicked() { } ui.horizontal(|ui| {} ); let mut volume: f32 = 100.0; ui.add(egui::Slider::new(&mut volume, 0.0..=100.0).text("Volume:")); if ui.button("Mute / Unmute").clicked() { } ui.horizontal(|ui| {} ); if ui.button("Pause / Unpause Game").clicked() { } if ui.button("Stop Emulator").clicked() { } if ui.button("Hard Reset").clicked() { } if ui.button("Soft Reset").clicked() { } if ui.button("Toggle Speed Limiter").clicked() { } ui.horizontal(|ui| {} ); if ui.button("View Log").clicked() { } }); ui.vertical(|ui| {} ); ui.menu_button("Settings", |ui| { if ui.button("Input Plugin and Config Path Selection").clicked() { } if ui.button("Emulator Core and Video Settings").clicked() { } if ui.button("Controller Setup").clicked() { } if ui.button("Hotkey Setup").clicked() { } }); ui.vertical(|ui| {} ); ui.menu_button("NetPlay", |ui| { if ui.button("Create Room").clicked() { } if ui.button("Join Room").clicked() { } }); ui.vertical(|ui| {} ); ui.menu_button("Community", |ui| { if ui.button("Join Discord Server").clicked() { } if ui.button("Support on Patreon").clicked() { } if ui.button("Support on GitHub").clicked() { } }); }); }); } } ``` ![image](https://github.com/user-attachments/assets/8a2f160c-1244-40e6-a6e6-ccc79ecccf72) ![image](https://github.com/user-attachments/assets/6b8e1b41-4a46-4ded-8230-522af842e902) ![image](https://github.com/user-attachments/assets/9599c6d7-6095-4f85-83d3-ca5373403875) ![image](https://github.com/user-attachments/assets/2e84932a-ac02-4e2b-bff3-f98f0490aa47) ![image](https://github.com/user-attachments/assets/51144ce1-795b-4217-a8b2-a6cfc95f2f43) ![image](https://github.com/user-attachments/assets/468ec242-2210-4cf2-8634-57c7bd45ff80) ![image](https://github.com/user-attachments/assets/70056002-ff60-40f3-aef1-11f18869bf1f) ![image](https://github.com/user-attachments/assets/097a5a98-50da-4b07-997a-eb8aff639002)
Author
Owner

@loganmc10 commented on GitHub (Mar 5, 2025):

@DarthSidious666 sorry I never got around to responding about this. It does look very nice.

Part of the problem, though, is that the emulation opens in a new window. I'm not sure that it is possible to embed an SDL window inside the egui window, so for the time being, it spawns a new window.

This means that the area under the menu is sort of "dead", which I think would seem strange. It would be alright if it had a ROM browser or something (I don't mean that I am asking you to do this, I am just commenting generally on the design).

I'm still hoping someone takes on this task of creating a new GUI for the app. It doesn't even need to be written in egui, if someone wants to delete the current GUI and use a different framework, that is also fine

<!-- gh-comment-id:2701863913 --> @loganmc10 commented on GitHub (Mar 5, 2025): @DarthSidious666 sorry I never got around to responding about this. It does look very nice. Part of the problem, though, is that the emulation opens in a new window. I'm not sure that it is possible to embed an SDL window inside the egui window, so for the time being, it spawns a new window. This means that the area under the menu is sort of "dead", which I think would seem strange. It would be alright if it had a ROM browser or something (I don't mean that I am asking you to do this, I am just commenting generally on the design). I'm still hoping someone takes on this task of creating a new GUI for the app. It doesn't even need to be written in egui, if someone wants to delete the current GUI and use a different framework, that is also fine
Author
Owner

@DarthSidious666 commented on GitHub (Mar 6, 2025):

@loganmc10 No worries, I hadn't realised that the emulation window was using SDL and I'm not all that competent in Rust to be able to help more.

If someone does manage to pick up the gauntlet then at least they'll have a starting point with the code posted here.
It should be adaptable enough for other frameworks.

<!-- gh-comment-id:2703293607 --> @DarthSidious666 commented on GitHub (Mar 6, 2025): @loganmc10 No worries, I hadn't realised that the emulation window was using SDL and I'm not all that competent in Rust to be able to help more. If someone does manage to pick up the gauntlet then at least they'll have a starting point with the code posted here. It should be adaptable enough for other frameworks.
Author
Owner

@bluchip-studio-official commented on GitHub (Mar 21, 2025):

egui window

would it work to modify the emulator to render to an offscreen framebuffer or texture instead of a window.

you could then extract the framebuffer pixels as a Vec or GPU texture then pass the pixel buffer to egui using its Image widget via Texture Handle.

I know it would create overhead copying pixels from CPU especially at higher frame rates but i am not sure if a lot of n64 games make it over the 30-40 fps?

<!-- gh-comment-id:2744439080 --> @bluchip-studio-official commented on GitHub (Mar 21, 2025): > egui window would it work to modify the emulator to render to an offscreen framebuffer or texture instead of a window. you could then extract the framebuffer pixels as a Vec or GPU texture then pass the pixel buffer to egui using its Image widget via Texture Handle. I know it would create overhead copying pixels from CPU especially at higher frame rates but i am not sure if a lot of n64 games make it over the 30-40 fps?
Author
Owner
<!-- gh-comment-id:2744493491 --> @Quackdoc commented on GitHub (Mar 21, 2025): I know sdl2 can do texture rendering which should eperformant enough. https://github.com/Rust-SDL2/rust-sdl2/issues/1178 https://docs.rs/sdl2/latest/sdl2/render/struct.Canvas.html#method.with_texture_canvas https://docs.rs/sdl3/latest/sdl3/render/struct.Canvas.html#method.with_texture_canvas
Author
Owner

@loganmc10 commented on GitHub (Mar 22, 2025):

I know it would create overhead copying pixels from CPU especially at higher frame rates but i am not sure if a lot of n64 games make it over the 30-40 fps?

All NTSC N64 games output (roughly) 60 images per second regardless of the internal framerate. On PAL it is roughly 50.

You are correct that copying the image from an offscreen framebuffer to the window would cause a performance hit.

Honestly, I don't think that the external game window is that big of a problem. Dolphin does this by default, although they do offer an option to render to the main window. I am more concerned about having an easy-to-use GUI for configuring controllers, setting options, choosing a game, etc... It would also be nice to have an interface for cheats as well

<!-- gh-comment-id:2745111791 --> @loganmc10 commented on GitHub (Mar 22, 2025): > I know it would create overhead copying pixels from CPU especially at higher frame rates but i am not sure if a lot of n64 games make it over the 30-40 fps? All NTSC N64 games output (roughly) 60 images per second regardless of the internal framerate. On PAL it is roughly 50. You are correct that copying the image from an offscreen framebuffer to the window would cause a performance hit. Honestly, I don't think that the external game window is that big of a problem. Dolphin does this by default, although they do offer an option to render to the main window. I am more concerned about having an easy-to-use GUI for configuring controllers, setting options, choosing a game, etc... It would also be nice to have an interface for cheats as well
Author
Owner

@PixelPenguin123143 commented on GitHub (Mar 26, 2025):

@loganmc10
Hi Logan, I wanted to let you know I'd be up to help you on the GUI of this emulator. I'm currently going to school for CS, I have experience coding mostly in python and java. I've worked as a UI developer intern on a web application written in python.

<!-- gh-comment-id:2755861787 --> @PixelPenguin123143 commented on GitHub (Mar 26, 2025): @loganmc10 Hi Logan, I wanted to let you know I'd be up to help you on the GUI of this emulator. I'm currently going to school for CS, I have experience coding mostly in python and java. I've worked as a UI developer intern on a web application written in python.
Author
Owner

@loganmc10 commented on GitHub (Mar 27, 2025):

Hi @PixelPenguin123143 that's good to hear. There is another person that goes by "wumput" on Discord that offered to help, but I don't know how much progress they've made. I would suggest joining the Discord server and getting in touch with wumput

<!-- gh-comment-id:2756857918 --> @loganmc10 commented on GitHub (Mar 27, 2025): Hi @PixelPenguin123143 that's good to hear. There is another person that goes by "wumput" on Discord that offered to help, but I don't know how much progress they've made. I would suggest joining the Discord server and getting in touch with wumput
Author
Owner

@loganmc10 commented on GitHub (Jun 12, 2025):

https://slint.dev/

<!-- gh-comment-id:2967004247 --> @loganmc10 commented on GitHub (Jun 12, 2025): https://slint.dev/
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/gopher64#5
No description provided.