tile/layer window in menu / also closable
This commit is contained in:
parent
6d5530efe6
commit
1b62211b90
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -487,7 +487,7 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
|||
[[package]]
|
||||
name = "cacao"
|
||||
version = "0.4.0-beta2"
|
||||
source = "git+https://github.com/italicsjenga/cacao#4fd93e3faeec5e80aef36779745b3506c9b5017d"
|
||||
source = "git+https://github.com/italicsjenga/cacao#65b32e79c0a8d088d19799b13e86634f3a64c10b"
|
||||
dependencies = [
|
||||
"bitmask-enum",
|
||||
"block2 0.2.0-alpha.6",
|
||||
|
@ -1639,6 +1639,7 @@ dependencies = [
|
|||
"gb-emu-lib",
|
||||
"objc2 0.3.0-beta.3",
|
||||
"raw-window-handle 0.5.2",
|
||||
"serde",
|
||||
"twinc_emu_vst",
|
||||
"uuid 1.6.1",
|
||||
]
|
||||
|
|
|
@ -158,7 +158,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let (sender, receiver) = channel::<EmulatorMessage>();
|
||||
let (sender, receiver) = channel::<EmulatorMessage<[u8; 4]>>();
|
||||
|
||||
{
|
||||
let sender = sender.clone();
|
||||
|
|
|
@ -16,7 +16,7 @@ use std::{
|
|||
path::PathBuf,
|
||||
sync::{mpsc::Receiver, Arc, Mutex, OnceLock},
|
||||
};
|
||||
use window::WindowManager;
|
||||
use window::{RendererChannel, WindowManager, WindowType};
|
||||
|
||||
pub mod audio;
|
||||
#[cfg(feature = "camera")]
|
||||
|
@ -103,7 +103,7 @@ where
|
|||
shader_path: Option<PathBuf>,
|
||||
resizable: bool,
|
||||
rom: Rom<C>,
|
||||
receiver: Receiver<EmulatorMessage>,
|
||||
receiver: Receiver<EmulatorMessage<[u8; 4]>>,
|
||||
camera: Arc<Mutex<CameraWrapper<C>>>,
|
||||
serial: SerialTarget,
|
||||
tile_window: bool,
|
||||
|
@ -112,7 +112,7 @@ where
|
|||
|
||||
pub fn prepare(
|
||||
options: RunOptions,
|
||||
receiver: Receiver<EmulatorMessage>,
|
||||
receiver: Receiver<EmulatorMessage<[u8; 4]>>,
|
||||
) -> PreparedEmulator<NoCamera> {
|
||||
let config = CONFIG_MANAGER.load_or_create_base_config();
|
||||
let standalone_config: StandaloneConfig = CONFIG_MANAGER.load_or_create_config();
|
||||
|
@ -180,21 +180,21 @@ where
|
|||
{
|
||||
let configs = access_config();
|
||||
|
||||
let window =
|
||||
window_manager.add_main(
|
||||
prepared.scale_override,
|
||||
prepared.shader_path,
|
||||
prepared.resizable,
|
||||
);
|
||||
let window = window_manager.add(
|
||||
WindowType::Main,
|
||||
prepared.scale_override,
|
||||
prepared.shader_path,
|
||||
prepared.resizable,
|
||||
);
|
||||
|
||||
let tile_window = if prepared.tile_window {
|
||||
Some(window_manager.add(configs.standalone_config.scale_factor, None, false))
|
||||
Some(new_tile_window(window_manager))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let layer_window = if prepared.layer_window {
|
||||
Some(window_manager.add(configs.standalone_config.scale_factor.min(2), None, false))
|
||||
Some(new_layer_window(window_manager))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -230,3 +230,27 @@ where
|
|||
|
||||
EmulatorCore::init(true, prepared.receiver, emulator_options, prepared.camera)
|
||||
}
|
||||
|
||||
pub fn new_tile_window<W>(window_manager: &mut W) -> RendererChannel
|
||||
where
|
||||
W: WindowManager,
|
||||
{
|
||||
window_manager.add(
|
||||
WindowType::Tile,
|
||||
access_config().standalone_config.scale_factor,
|
||||
None,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_layer_window<W>(window_manager: &mut W) -> RendererChannel
|
||||
where
|
||||
W: WindowManager,
|
||||
{
|
||||
window_manager.add(
|
||||
WindowType::Layer,
|
||||
access_config().standalone_config.scale_factor.min(2),
|
||||
None,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -6,15 +6,17 @@ pub mod winit_manager;
|
|||
|
||||
pub type RendererChannel = Sender<RendererMessage<[u8; 4]>>;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum WindowType {
|
||||
Main,
|
||||
Tile,
|
||||
Layer,
|
||||
}
|
||||
|
||||
pub trait WindowManager {
|
||||
fn add_main(
|
||||
&mut self,
|
||||
factor: usize,
|
||||
shader_path: Option<PathBuf>,
|
||||
resizable: bool,
|
||||
) -> RendererChannel;
|
||||
fn add(
|
||||
&mut self,
|
||||
window_type: WindowType,
|
||||
factor: usize,
|
||||
shader_path: Option<PathBuf>,
|
||||
resizable: bool,
|
||||
|
|
|
@ -28,7 +28,7 @@ use winit_input_helper::WinitInputHelper;
|
|||
|
||||
use crate::access_config;
|
||||
|
||||
use super::{RendererChannel, WindowManager};
|
||||
use super::{RendererChannel, WindowManager, WindowType};
|
||||
|
||||
pub struct WinitWindowManager {
|
||||
event_loop: EventLoop<()>,
|
||||
|
@ -41,14 +41,18 @@ struct WinitWindowManagerData {
|
|||
windows: HashMap<WindowId, WindowRenderer>,
|
||||
window_data_manager: Arc<RendererBackendManager>,
|
||||
input: WinitInputHelper,
|
||||
sender: Sender<EmulatorMessage>,
|
||||
sender: Sender<EmulatorMessage<[u8; 4]>>,
|
||||
gamepad_handler: Gilrs,
|
||||
joypad_state: JoypadState,
|
||||
_stream: Stream,
|
||||
}
|
||||
|
||||
impl WinitWindowManager {
|
||||
pub fn new(sender: Sender<EmulatorMessage>, _stream: Stream, record_main: bool) -> Self {
|
||||
pub fn new(
|
||||
sender: Sender<EmulatorMessage<[u8; 4]>>,
|
||||
_stream: Stream,
|
||||
record_main: bool,
|
||||
) -> Self {
|
||||
let event_loop = EventLoop::new().unwrap();
|
||||
#[cfg(feature = "vulkan")]
|
||||
let window_data_manager =
|
||||
|
@ -83,35 +87,22 @@ impl WinitWindowManager {
|
|||
}
|
||||
|
||||
impl WindowManager for WinitWindowManager {
|
||||
fn add_main(
|
||||
&mut self,
|
||||
factor: usize,
|
||||
shader_path: Option<PathBuf>,
|
||||
resizable: bool,
|
||||
) -> RendererChannel {
|
||||
self.data.add(
|
||||
factor,
|
||||
shader_path,
|
||||
resizable,
|
||||
&self.event_loop,
|
||||
true,
|
||||
self.record_main,
|
||||
)
|
||||
}
|
||||
|
||||
fn add(
|
||||
&mut self,
|
||||
window_type: WindowType,
|
||||
factor: usize,
|
||||
shader_path: Option<PathBuf>,
|
||||
resizable: bool,
|
||||
) -> RendererChannel {
|
||||
let is_main = window_type == WindowType::Main;
|
||||
|
||||
self.data.add(
|
||||
factor,
|
||||
shader_path,
|
||||
resizable,
|
||||
&self.event_loop,
|
||||
false,
|
||||
false,
|
||||
is_main,
|
||||
is_main && self.record_main,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ struct EmuVars {
|
|||
}
|
||||
|
||||
struct EmuComms {
|
||||
sender: Sender<EmulatorMessage>,
|
||||
sender: Sender<EmulatorMessage<[u8; 4]>>,
|
||||
receiver: Receiver<RendererMessage<[u8; 4]>>,
|
||||
}
|
||||
|
||||
|
@ -288,7 +288,7 @@ impl Plugin for GameboyEmu {
|
|||
let _ =
|
||||
IS_CGB.set(rom.rom_type == CgbRomType::CgbOnly || configs.emu_config.prefer_cgb);
|
||||
|
||||
let (sender, receiver) = channel::<EmulatorMessage>();
|
||||
let (sender, receiver) = channel::<EmulatorMessage<[u8; 4]>>();
|
||||
|
||||
let (output, rx) = AudioOutput::new(
|
||||
buffer_config.sample_rate,
|
||||
|
|
|
@ -21,3 +21,4 @@ objc = { version = "=0.3.0-beta.3", package = "objc2" }
|
|||
uuid = { version = "1.6", features = ["v4", "fast-rng"] }
|
||||
raw-window-handle = { version = "0.5" }
|
||||
cpal = "0.15"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
|
|
@ -16,7 +16,10 @@ use cacao::{
|
|||
core_foundation::base::TCFTypeRef,
|
||||
};
|
||||
use cpal::Stream;
|
||||
use frontend_common::window::{RendererChannel, WindowManager};
|
||||
use frontend_common::{
|
||||
new_layer_window, new_tile_window,
|
||||
window::{RendererChannel, WindowManager, WindowType},
|
||||
};
|
||||
use gb_emu_lib::{
|
||||
connect::{EmulatorMessage, JoypadButtons, JoypadState, RendererMessage, ResolutionData},
|
||||
renderer::{RendererBackend, RendererBackendManager, WindowOptions},
|
||||
|
@ -25,16 +28,15 @@ use raw_window_handle::{
|
|||
AppKitDisplayHandle, AppKitWindowHandle, HasRawDisplayHandle, HasRawWindowHandle,
|
||||
RawDisplayHandle, RawWindowHandle,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::{dispatch, AppMessage};
|
||||
use super::{dispatch, AppMessage, CoreMessage};
|
||||
|
||||
pub enum EmuWindowMessage {
|
||||
Closing {
|
||||
id: Uuid,
|
||||
window_type: WindowType,
|
||||
},
|
||||
Renderer {
|
||||
id: Uuid,
|
||||
window_type: WindowType,
|
||||
renderer_message: RendererMessage<[u8; 4]>,
|
||||
},
|
||||
KeyDown(JoypadButtons),
|
||||
|
@ -42,13 +44,13 @@ pub enum EmuWindowMessage {
|
|||
}
|
||||
|
||||
pub struct EmulatorHandles {
|
||||
sender: Sender<EmulatorMessage>,
|
||||
sender: Sender<EmulatorMessage<[u8; 4]>>,
|
||||
emulator_thread: Option<JoinHandle<()>>,
|
||||
_stream: Stream,
|
||||
}
|
||||
|
||||
impl EmulatorHandles {
|
||||
fn new(sender: Sender<EmulatorMessage>, stream: Stream) -> Self {
|
||||
fn new(sender: Sender<EmulatorMessage<[u8; 4]>>, stream: Stream) -> Self {
|
||||
Self {
|
||||
sender,
|
||||
emulator_thread: None,
|
||||
|
@ -149,7 +151,7 @@ fn get_buttons(event: &Event) -> Option<JoypadButtons> {
|
|||
|
||||
pub struct CacaoWindowManager {
|
||||
backend_manager: Arc<RendererBackendManager>,
|
||||
windows: HashMap<Uuid, Window<CacaoWindow>>,
|
||||
windows: HashMap<WindowType, Window<CacaoWindow>>,
|
||||
handles: Option<EmulatorHandles>,
|
||||
joypad_state: JoypadState,
|
||||
_button_handler: ButtonHandler,
|
||||
|
@ -172,7 +174,7 @@ impl CacaoWindowManager {
|
|||
self.handles.is_some()
|
||||
}
|
||||
|
||||
pub fn update_handles(&mut self, sender: Sender<EmulatorMessage>, stream: Stream) {
|
||||
pub fn update_handles(&mut self, sender: Sender<EmulatorMessage<[u8; 4]>>, stream: Stream) {
|
||||
self.handles = Some(EmulatorHandles::new(sender, stream));
|
||||
}
|
||||
|
||||
|
@ -184,17 +186,32 @@ impl CacaoWindowManager {
|
|||
|
||||
pub fn message(&mut self, message: EmuWindowMessage) {
|
||||
match message {
|
||||
EmuWindowMessage::Closing { id } => {
|
||||
self.windows.remove(&id);
|
||||
if self.windows.is_empty() {
|
||||
let _ = self.handles.take();
|
||||
}
|
||||
EmuWindowMessage::Closing { window_type } => {
|
||||
self.windows.remove(&window_type);
|
||||
match window_type {
|
||||
WindowType::Main => {
|
||||
let _ = self.handles.take();
|
||||
for (_, w) in self.windows.drain() {
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
WindowType::Tile => {
|
||||
if self.is_emulator_running() {
|
||||
dispatch(AppMessage::Core(CoreMessage::SetTileWindow(false)))
|
||||
}
|
||||
}
|
||||
WindowType::Layer => {
|
||||
if self.is_emulator_running() {
|
||||
dispatch(AppMessage::Core(CoreMessage::SetLayerWindow(false)))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
EmuWindowMessage::Renderer {
|
||||
id,
|
||||
window_type,
|
||||
renderer_message,
|
||||
} => {
|
||||
if let Some(window) = self.windows.get_mut(&id) {
|
||||
if let Some(window) = self.windows.get_mut(&window_type) {
|
||||
if let Some(delegate) = window.delegate.as_mut() {
|
||||
delegate.message(
|
||||
renderer_message,
|
||||
|
@ -232,25 +249,52 @@ impl CacaoWindowManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_layer_window(&mut self, state: bool) {
|
||||
if state {
|
||||
let is_running = self.is_emulator_running();
|
||||
if is_running {
|
||||
let new_layer_window = new_layer_window(self);
|
||||
if let Some(ref handles) = self.handles {
|
||||
handles
|
||||
.sender
|
||||
.send(EmulatorMessage::NewLayerWindow(new_layer_window))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_tile_window(&mut self, state: bool) {
|
||||
if state {
|
||||
let is_running = self.is_emulator_running();
|
||||
if is_running {
|
||||
let new_tile_window = new_tile_window(self);
|
||||
if let Some(ref handles) = self.handles {
|
||||
handles
|
||||
.sender
|
||||
.send(EmulatorMessage::NewTileWindow(new_tile_window))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowManager for CacaoWindowManager {
|
||||
fn add_main(
|
||||
&mut self,
|
||||
factor: usize,
|
||||
shader_path: Option<std::path::PathBuf>,
|
||||
resizable: bool,
|
||||
) -> RendererChannel {
|
||||
self.add(factor, shader_path, resizable)
|
||||
}
|
||||
|
||||
fn add(
|
||||
&mut self,
|
||||
window_type: WindowType,
|
||||
factor: usize,
|
||||
shader_path: Option<std::path::PathBuf>,
|
||||
resizable: bool,
|
||||
) -> RendererChannel {
|
||||
let (w, receiver) = CacaoWindow::new(factor, shader_path, self.backend_manager.clone());
|
||||
let (w, receiver) = CacaoWindow::new(
|
||||
window_type,
|
||||
factor,
|
||||
shader_path,
|
||||
self.backend_manager.clone(),
|
||||
);
|
||||
let window = Window::with(
|
||||
{
|
||||
let mut config = WindowConfig::default();
|
||||
|
@ -272,7 +316,7 @@ impl WindowManager for CacaoWindowManager {
|
|||
);
|
||||
window.show();
|
||||
self.windows
|
||||
.insert(window.delegate.as_ref().unwrap().id, window);
|
||||
.insert(window.delegate.as_ref().unwrap().window_type, window);
|
||||
receiver
|
||||
}
|
||||
}
|
||||
|
@ -290,20 +334,19 @@ enum MonitorThreadState {
|
|||
}
|
||||
|
||||
impl MonitorThread {
|
||||
fn new(receiver: Receiver<RendererMessage<[u8; 4]>>, id: Uuid) -> Self {
|
||||
fn new(receiver: Receiver<RendererMessage<[u8; 4]>>, window_type: WindowType) -> Self {
|
||||
let (destroy, destroy_recv) = mpsc::channel();
|
||||
let thread =
|
||||
std::thread::spawn(move || loop {
|
||||
if let Ok(renderer_message) = receiver.recv() {
|
||||
dispatch(AppMessage::EmuWindow(EmuWindowMessage::Renderer {
|
||||
id,
|
||||
renderer_message,
|
||||
}));
|
||||
}
|
||||
if let Ok(true) = destroy_recv.try_recv() {
|
||||
return;
|
||||
}
|
||||
});
|
||||
let thread = std::thread::spawn(move || loop {
|
||||
if let Ok(renderer_message) = receiver.recv() {
|
||||
dispatch(AppMessage::EmuWindow(EmuWindowMessage::Renderer {
|
||||
window_type,
|
||||
renderer_message,
|
||||
}));
|
||||
}
|
||||
if let Ok(true) = destroy_recv.try_recv() {
|
||||
return;
|
||||
}
|
||||
});
|
||||
Self {
|
||||
state: MonitorThreadState::Live { thread, destroy },
|
||||
}
|
||||
|
@ -326,7 +369,7 @@ impl Drop for MonitorThread {
|
|||
}
|
||||
|
||||
struct CacaoWindow {
|
||||
id: Uuid,
|
||||
window_type: WindowType,
|
||||
backend_manager: Arc<RendererBackendManager>,
|
||||
backend: Option<RendererBackend>,
|
||||
scale_factor: usize,
|
||||
|
@ -337,16 +380,16 @@ struct CacaoWindow {
|
|||
|
||||
impl CacaoWindow {
|
||||
fn new(
|
||||
window_type: WindowType,
|
||||
scale_factor: usize,
|
||||
shader_path: Option<std::path::PathBuf>,
|
||||
backend_manager: Arc<RendererBackendManager>,
|
||||
) -> (Self, RendererChannel) {
|
||||
let id = Uuid::new_v4();
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
let channel_thread = MonitorThread::new(receiver, id);
|
||||
let channel_thread = MonitorThread::new(receiver, window_type);
|
||||
(
|
||||
Self {
|
||||
id,
|
||||
window_type,
|
||||
backend_manager,
|
||||
backend: None,
|
||||
scale_factor,
|
||||
|
@ -413,7 +456,9 @@ impl WindowDelegate for CacaoWindow {
|
|||
}
|
||||
|
||||
fn will_close(&self) {
|
||||
dispatch(AppMessage::EmuWindow(EmuWindowMessage::Closing { id: self.id }));
|
||||
dispatch(AppMessage::EmuWindow(EmuWindowMessage::Closing {
|
||||
window_type: self.window_type,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,10 @@ use cacao::appkit::{App, AppDelegate};
|
|||
use cacao::filesystem::FileSelectPanel;
|
||||
use cacao::notification_center::Dispatcher;
|
||||
use frontend_common::audio;
|
||||
use gb_emu_lib::config::{NamedConfig, CONFIG_MANAGER};
|
||||
use gb_emu_lib::connect::{EmulatorCoreTrait, EmulatorMessage};
|
||||
use raw_window_handle::{AppKitDisplayHandle, RawDisplayHandle};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use self::cacao_window_manager::{CacaoWindowManager, EmuWindowMessage};
|
||||
use self::preferences::{PreferencesMessage, PreferencesUi};
|
||||
|
@ -25,13 +27,31 @@ pub(crate) enum AppMessage {
|
|||
|
||||
pub(crate) enum CoreMessage {
|
||||
ShowOpenDialog,
|
||||
ToggleTileWindow,
|
||||
ToggleLayerWindow,
|
||||
SetTileWindow(bool),
|
||||
SetLayerWindow(bool),
|
||||
OpenPreferences,
|
||||
OpenRom(PathBuf),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
||||
#[serde(default)]
|
||||
pub struct MacGuiConfig {
|
||||
pub tile_window: bool,
|
||||
pub layer_window: bool,
|
||||
}
|
||||
|
||||
impl NamedConfig for MacGuiConfig {
|
||||
fn name() -> String {
|
||||
String::from("mac-gui")
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TwincUiApp {
|
||||
preferences: RwLock<Window<PreferencesUi>>,
|
||||
current_game: RwLock<CacaoWindowManager>,
|
||||
gui_config: RwLock<MacGuiConfig>,
|
||||
}
|
||||
|
||||
impl TwincUiApp {
|
||||
|
@ -75,13 +95,14 @@ impl Default for TwincUiApp {
|
|||
current_game: RwLock::new(
|
||||
CacaoWindowManager::new(RawDisplayHandle::AppKit(AppKitDisplayHandle::empty()))
|
||||
),
|
||||
gui_config: RwLock::new(CONFIG_MANAGER.load_or_create_config()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AppDelegate for TwincUiApp {
|
||||
fn did_finish_launching(&self) {
|
||||
App::set_menu(menu());
|
||||
App::set_menu(menu(&self.gui_config.read().unwrap()));
|
||||
App::activate();
|
||||
}
|
||||
}
|
||||
|
@ -95,11 +116,57 @@ impl Dispatcher for TwincUiApp {
|
|||
AppMessage::Core(CoreMessage::OpenPreferences) => {
|
||||
self.preferences.read().unwrap().show();
|
||||
}
|
||||
AppMessage::Core(CoreMessage::ToggleLayerWindow) => {
|
||||
if let Ok(mut config) = self.gui_config.write() {
|
||||
config.layer_window = !config.layer_window;
|
||||
App::set_menu(menu(&config));
|
||||
let _ = CONFIG_MANAGER.save_custom_config(config.clone());
|
||||
if let Ok(mut current_game) = self.current_game.write() {
|
||||
current_game.set_layer_window(config.layer_window);
|
||||
}
|
||||
}
|
||||
}
|
||||
AppMessage::Core(CoreMessage::ToggleTileWindow) => {
|
||||
if let Ok(mut config) = self.gui_config.write() {
|
||||
config.tile_window = !config.tile_window;
|
||||
App::set_menu(menu(&config));
|
||||
let _ = CONFIG_MANAGER.save_custom_config(config.clone());
|
||||
if let Ok(mut current_game) = self.current_game.write() {
|
||||
current_game.set_tile_window(config.tile_window);
|
||||
}
|
||||
}
|
||||
}
|
||||
AppMessage::Core(CoreMessage::SetLayerWindow(val)) => {
|
||||
if let Ok(mut config) = self.gui_config.write() {
|
||||
config.layer_window = val;
|
||||
App::set_menu(menu(&config));
|
||||
let _ = CONFIG_MANAGER.save_custom_config(config.clone());
|
||||
if let Ok(mut current_game) = self.current_game.write() {
|
||||
current_game.set_layer_window(config.layer_window);
|
||||
}
|
||||
}
|
||||
}
|
||||
AppMessage::Core(CoreMessage::SetTileWindow(val)) => {
|
||||
if let Ok(mut config) = self.gui_config.write() {
|
||||
config.tile_window = val;
|
||||
App::set_menu(menu(&config));
|
||||
let _ = CONFIG_MANAGER.save_custom_config(config.clone());
|
||||
if let Ok(mut current_game) = self.current_game.write() {
|
||||
current_game.set_tile_window(config.tile_window);
|
||||
}
|
||||
}
|
||||
}
|
||||
AppMessage::Core(CoreMessage::OpenRom(path)) => {
|
||||
let (sender, receiver) = channel::<EmulatorMessage>();
|
||||
let (sender, receiver) = channel::<EmulatorMessage<[u8; 4]>>();
|
||||
sender.send(EmulatorMessage::Start).unwrap();
|
||||
let prepared =
|
||||
frontend_common::prepare(frontend_common::RunOptions::new(path), receiver);
|
||||
|
||||
let mut options = frontend_common::RunOptions::new(path);
|
||||
if let Ok(config) = self.gui_config.read() {
|
||||
options.layer_window = config.layer_window;
|
||||
options.tile_window = config.tile_window
|
||||
}
|
||||
|
||||
let prepared = frontend_common::prepare(options, receiver);
|
||||
let (output, stream) = audio::create_output(false);
|
||||
let mut window_manager = self.current_game.write().unwrap();
|
||||
window_manager.update_handles(sender, stream);
|
||||
|
@ -130,7 +197,7 @@ impl Dispatcher for TwincUiApp {
|
|||
}
|
||||
}
|
||||
|
||||
fn menu() -> Vec<Menu> {
|
||||
fn menu(config: &MacGuiConfig) -> Vec<Menu> {
|
||||
vec![
|
||||
Menu::new(
|
||||
"",
|
||||
|
@ -159,6 +226,13 @@ fn menu() -> Vec<Menu> {
|
|||
Menu::new(
|
||||
"Window",
|
||||
vec![
|
||||
MenuItem::new("Tiles")
|
||||
.checkmark(config.tile_window)
|
||||
.action(|| dispatch(AppMessage::Core(CoreMessage::ToggleTileWindow))),
|
||||
MenuItem::new("Layers")
|
||||
.checkmark(config.layer_window)
|
||||
.action(|| dispatch(AppMessage::Core(CoreMessage::ToggleLayerWindow))),
|
||||
MenuItem::Separator,
|
||||
MenuItem::Minimize,
|
||||
MenuItem::Separator,
|
||||
MenuItem::new("Bring All to Front"),
|
||||
|
|
|
@ -14,11 +14,16 @@ pub use crate::{HEIGHT, WIDTH};
|
|||
use async_ringbuf::{AsyncHeapConsumer, AsyncHeapProducer, AsyncHeapRb};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EmulatorMessage {
|
||||
pub enum EmulatorMessage<ColourFormat>
|
||||
where
|
||||
ColourFormat: From<Colour> + Copy,
|
||||
{
|
||||
Start,
|
||||
Pause,
|
||||
Exit,
|
||||
JoypadUpdate(JoypadState),
|
||||
NewLayerWindow(Sender<RendererMessage<ColourFormat>>),
|
||||
NewTileWindow(Sender<RendererMessage<ColourFormat>>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
|
|
@ -38,7 +38,7 @@ where
|
|||
ColourFormat: From<Colour> + Copy,
|
||||
C: PocketCamera + Send + 'static,
|
||||
{
|
||||
receiver: Receiver<EmulatorMessage>,
|
||||
receiver: Receiver<EmulatorMessage<ColourFormat>>,
|
||||
cpu: Cpu<ColourFormat, C>,
|
||||
paused: bool,
|
||||
spooky: PhantomData<C>,
|
||||
|
@ -51,7 +51,7 @@ where
|
|||
{
|
||||
pub fn init(
|
||||
paused: bool,
|
||||
receiver: Receiver<EmulatorMessage>,
|
||||
receiver: Receiver<EmulatorMessage<ColourFormat>>,
|
||||
options: EmulatorOptions<ColourFormat, C>,
|
||||
camera: Arc<Mutex<CameraWrapper<C>>>,
|
||||
) -> Self {
|
||||
|
@ -59,13 +59,13 @@ where
|
|||
|
||||
let is_cgb_mode = rom.rom_type == CgbRomType::CgbOnly || options.cgb_mode;
|
||||
let bootrom = if is_cgb_mode {
|
||||
options.cgb_bootrom.unwrap_or(RomFile::Raw(
|
||||
include_bytes!("../../sameboy-bootroms/cgb_boot.bin").to_vec(),
|
||||
))
|
||||
options.cgb_bootrom.unwrap_or(
|
||||
RomFile::Raw(include_bytes!("../../sameboy-bootroms/cgb_boot.bin").to_vec())
|
||||
)
|
||||
} else {
|
||||
options.dmg_bootrom.unwrap_or(RomFile::Raw(
|
||||
include_bytes!("../../sameboy-bootroms/dmg_boot.bin").to_vec(),
|
||||
))
|
||||
options.dmg_bootrom.unwrap_or(
|
||||
RomFile::Raw(include_bytes!("../../sameboy-bootroms/dmg_boot.bin").to_vec())
|
||||
)
|
||||
}
|
||||
.load_data()
|
||||
.expect("Error loading bootrom!");
|
||||
|
@ -111,7 +111,11 @@ where
|
|||
)
|
||||
}
|
||||
|
||||
fn new(paused: bool, receiver: Receiver<EmulatorMessage>, cpu: Cpu<ColourFormat, C>) -> Self {
|
||||
fn new(
|
||||
paused: bool,
|
||||
receiver: Receiver<EmulatorMessage<ColourFormat>>,
|
||||
cpu: Cpu<ColourFormat, C>,
|
||||
) -> Self {
|
||||
Self {
|
||||
receiver,
|
||||
cpu,
|
||||
|
@ -169,7 +173,7 @@ where
|
|||
false
|
||||
}
|
||||
|
||||
fn process_message(&mut self, msg: EmulatorMessage) -> bool {
|
||||
fn process_message(&mut self, msg: EmulatorMessage<ColourFormat>) -> bool {
|
||||
match msg {
|
||||
EmulatorMessage::Exit => {
|
||||
self.cpu.memory.flush_rom();
|
||||
|
@ -180,6 +184,8 @@ where
|
|||
EmulatorMessage::JoypadUpdate(new_state) => {
|
||||
self.cpu.next_joypad_state = Some(new_state)
|
||||
}
|
||||
EmulatorMessage::NewLayerWindow(new) => self.cpu.memory.gpu.set_layer_window(new),
|
||||
EmulatorMessage::NewTileWindow(new) => self.cpu.memory.gpu.set_tile_window(new),
|
||||
}
|
||||
false
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ where
|
|||
pub(super) user_mode: bool,
|
||||
oam_dma: OamDma,
|
||||
joypad: Joypad,
|
||||
gpu: Gpu<ColourFormat>,
|
||||
pub gpu: Gpu<ColourFormat>,
|
||||
apu: Apu,
|
||||
serial: Serial,
|
||||
timers: Timer,
|
||||
|
@ -290,11 +290,13 @@ where
|
|||
fn get_io(&self, address: IoAddress) -> u8 {
|
||||
match address {
|
||||
IoAddress::Joypad => self.joypad.as_register(),
|
||||
IoAddress::Serial(address) => match address.inner() {
|
||||
0xFF01 => self.serial.get_queued(),
|
||||
0xFF02 => self.serial.get_control(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
IoAddress::Serial(address) => {
|
||||
match address.inner() {
|
||||
0xFF01 => self.serial.get_queued(),
|
||||
0xFF02 => self.serial.get_control(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
IoAddress::Timer(address) => match address.inner() {
|
||||
0xFF04 => self.timers.get_div(),
|
||||
0xFF05 => self.timers.get_tima(),
|
||||
|
|
|
@ -123,6 +123,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_tile_window(&mut self, window: Sender<RendererMessage<ColourFormat>>) {
|
||||
self.tile_window = Some(TileWindow::new(window, self.cgb_data.is_some()));
|
||||
}
|
||||
|
||||
pub fn set_layer_window(&mut self, window: Sender<RendererMessage<ColourFormat>>) {
|
||||
self.layer_window = Some(LayerWindow::new(window, self.cgb_data.is_some()));
|
||||
}
|
||||
|
||||
pub(crate) fn get_mode(&self) -> DrawMode {
|
||||
self.stat.mode
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue