diff --git a/crates/molotov-gui/src/app.rs b/crates/molotov-gui/src/app.rs new file mode 100644 index 0000000..46591b8 --- /dev/null +++ b/crates/molotov-gui/src/app.rs @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +use eframe::egui; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Tab { + Play, + FastFlags, + Mods, + Audio, + MultiInstance, + Maintenance, +} + +pub struct MolotovApp { + current_tab: Tab, + pub safe_mode: bool, + pub fps_cap: i64, + pub vram_skip_mips: bool, +} + +impl Default for MolotovApp { + fn default() -> Self { + Self { + current_tab: Tab::Play, + safe_mode: false, + fps_cap: 144, + vram_skip_mips: false, + } + } +} + +impl MolotovApp { + pub fn active_tab_name(&self) -> &'static str { + match self.current_tab { + Tab::Play => "Play", + Tab::FastFlags => "FastFlags", + Tab::Mods => "Mods", + Tab::Audio => "Audio & Voice", + Tab::MultiInstance => "Instances", + Tab::Maintenance => "Maintenance", + } + } +} + +impl eframe::App for MolotovApp { + fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { + ui.horizontal(|ui| { + ui.selectable_value(&mut self.current_tab, Tab::Play, "๐ŸŽฎ Play"); + ui.selectable_value(&mut self.current_tab, Tab::FastFlags, "โš™๏ธ FastFlags"); + ui.selectable_value(&mut self.current_tab, Tab::Mods, "๐ŸŽจ Mods"); + ui.selectable_value(&mut self.current_tab, Tab::Audio, "๐ŸŽ™๏ธ Audio"); + ui.selectable_value(&mut self.current_tab, Tab::MultiInstance, "๐Ÿ‘ฅ Instances"); + ui.selectable_value(&mut self.current_tab, Tab::Maintenance, "๐Ÿงน Maintenance"); + }); + }); + + egui::CentralPanel::default().show(ctx, |ui| match self.current_tab { + Tab::Play => { + ui.heading("Molotov Roblox Runtime"); + ui.checkbox(&mut self.safe_mode, "Safe Mode (Minimal Flags)"); + if ui.button("๐Ÿš€ Launch Roblox").clicked() { + println!("Launch clicked!"); + } + } + Tab::FastFlags => { + ui.heading("Performance & FastFlags"); + ui.add(egui::Slider::new(&mut self.fps_cap, 30..=360).text("Target FPS")); + ui.checkbox(&mut self.vram_skip_mips, "Reduce VRAM Texture Mipmaps (NVIDIA fix)"); + } + Tab::Mods => { + ui.heading("Asset Mods (In-Memory)"); + ui.label("Drop custom ouch.ogg or cursors into ~/.config/molotov/mods/"); + } + Tab::Audio => { + ui.heading("PipeWire Voice Chat"); + ui.label("Microphone active stream is destroyed on pause to prevent indicator leaks."); + } + Tab::MultiInstance => { + ui.heading("Multi-Instance Sandboxing (bubblewrap)"); + ui.label("Launch isolated accounts in independent namespaces."); + } + Tab::Maintenance => { + ui.heading("Maintenance & Cleaning"); + if ui.button("Clean Stale Versions").clicked() { + println!("Clean clicked!"); + } + } + }); + } +} diff --git a/crates/molotov-gui/src/lib.rs b/crates/molotov-gui/src/lib.rs index 6d9dd2e..68c18f6 100644 --- a/crates/molotov-gui/src/lib.rs +++ b/crates/molotov-gui/src/lib.rs @@ -1,4 +1,19 @@ // SPDX-License-Identifier: GPL-3.0-or-later +pub mod app; +use app::MolotovApp; + pub fn run() { - println!("Molotov GUI placeholder"); + let native_options = eframe::NativeOptions { + viewport: eframe::egui::ViewportBuilder::default() + .with_inner_size([720.0, 480.0]) + .with_min_inner_size([600.0, 400.0]) + .with_title("Molotov - Roblox Runtime for Linux"), + ..Default::default() + }; + + let _ = eframe::run_native( + "Molotov", + native_options, + Box::new(|_cc| Ok(Box::new(MolotovApp::default()))), + ); } diff --git a/crates/molotov-gui/tests/gui_test.rs b/crates/molotov-gui/tests/gui_test.rs new file mode 100644 index 0000000..c5f21d1 --- /dev/null +++ b/crates/molotov-gui/tests/gui_test.rs @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +use molotov_gui::app::MolotovApp; + +#[test] +fn test_gui_default_tab_is_play() { + let app = MolotovApp::default(); + assert_eq!(app.active_tab_name(), "Play"); +}