diff --git a/ewm/src/boo.rs b/ewm/src/boo.rs index 551414e..eaa528f 100644 --- a/ewm/src/boo.rs +++ b/ewm/src/boo.rs @@ -4,6 +4,7 @@ use sdl3::event::Event; use sdl3::keyboard::Keycode; use sdl3::pixels::{Color, PixelFormat}; +use sdl3::rect::Rect; use sdl3::render::ScaleMode; use sdl3::sys::render::SDL_RendererLogicalPresentation; @@ -48,6 +49,8 @@ static MENU: [&str; TTY_ROWS] = [ ]; pub fn main(_args: &[String]) -> BooChoice { + let pad = sdl::window_padding(); + // Setup SDL let context = match sdl3::init() { @@ -60,7 +63,11 @@ pub fn main(_args: &[String]) -> BooChoice { let video = context.video().expect("Failed to initialize SDL video"); let window = video - .window("EWM v0.1 - Bootloader", 280 * 3, 192 * 3) + .window( + "EWM v0.1 - Bootloader", + 280 * 3 + 2 * pad, + 192 * 3 + 2 * pad, + ) .position_centered() .build() .expect("Failed create window"); @@ -72,10 +79,12 @@ pub fn main(_args: &[String]) -> BooChoice { return BooChoice::Quit; } + // Logical units are window pixels: the tty texture is drawn at 3x into + // an explicit rect, leaving pad window pixels around it. canvas .set_logical_size( - TTY_PIXEL_WIDTH as u32, - TTY_PIXEL_HEIGHT as u32, + TTY_PIXEL_WIDTH as u32 * 3 + 2 * pad, + TTY_PIXEL_HEIGHT as u32 * 3 + 2 * pad, SDL_RendererLogicalPresentation::LETTERBOX, ) .expect("Failed to set logical size"); @@ -140,8 +149,14 @@ pub fn main(_args: &[String]) -> BooChoice { texture .update(None, &bytes, TTY_PIXEL_WIDTH * 4) .expect("Failed to update texture"); + let dst = Rect::new( + pad as i32, + pad as i32, + TTY_PIXEL_WIDTH as u32 * 3, + TTY_PIXEL_HEIGHT as u32 * 3, + ); canvas - .copy(&texture, None, None) + .copy(&texture, None, dst) .expect("Failed to copy texture"); canvas.present(); diff --git a/ewm/src/one.rs b/ewm/src/one.rs index 0736e6f..ed7e5e1 100644 --- a/ewm/src/one.rs +++ b/ewm/src/one.rs @@ -12,6 +12,7 @@ use ewm_core::mem::{DeviceHandle, Memory}; use sdl3::event::Event; use sdl3::keyboard::{Keycode, Mod}; use sdl3::pixels::PixelFormat; +use sdl3::rect::Rect; use sdl3::render::ScaleMode; use sdl3::sys::render::SDL_RendererLogicalPresentation; use sdl3::video::FullscreenType; @@ -197,6 +198,8 @@ fn step_cpu(one: &mut One, cycles: u32) { } pub fn main(args: &[String]) -> i32 { + let pad = sdl::window_padding(); + // Parse Apple 1 specific options. The C default model is the Replica 1. let mut model = OneModel::Replica1; let mut memory: Vec = Vec::new(); @@ -252,7 +255,7 @@ pub fn main(args: &[String]) -> i32 { let video = context.video().expect("Failed to initialize SDL video"); let window = video - .window("EWM v0.1 - Apple 1", 280 * 3, 192 * 3) + .window("EWM v0.1 - Apple 1", 280 * 3 + 2 * pad, 192 * 3 + 2 * pad) .position_centered() .build(); let window = match window { @@ -270,10 +273,12 @@ pub fn main(args: &[String]) -> i32 { return 1; } + // Logical units are window pixels: the tty texture is drawn at 3x into + // an explicit rect, leaving pad window pixels around it. canvas .set_logical_size( - TTY_PIXEL_WIDTH as u32, - TTY_PIXEL_HEIGHT as u32, + TTY_PIXEL_WIDTH as u32 * 3 + 2 * pad, + TTY_PIXEL_HEIGHT as u32 * 3 + 2 * pad, SDL_RendererLogicalPresentation::LETTERBOX, ) .expect("Failed to set logical size"); @@ -375,8 +380,14 @@ pub fn main(args: &[String]) -> i32 { texture .update(None, &bytes, TTY_PIXEL_WIDTH * 4) .expect("Failed to update texture"); + let dst = Rect::new( + pad as i32, + pad as i32, + TTY_PIXEL_WIDTH as u32 * 3, + TTY_PIXEL_HEIGHT as u32 * 3, + ); canvas - .copy(&texture, None, None) + .copy(&texture, None, dst) .expect("Failed to copy texture"); canvas.present(); diff --git a/ewm/src/sdl.rs b/ewm/src/sdl.rs index 6829ae4..fde35cf 100644 --- a/ewm/src/sdl.rs +++ b/ewm/src/sdl.rs @@ -53,6 +53,15 @@ pub fn check_renderer(canvas: &WindowCanvas) -> Result<(), String> { Ok(()) } +/// Window pixels between the screen contents and the window border, +/// from `EWM_WINDOW_PADDING` (default 4). +pub fn window_padding() -> u32 { + std::env::var("EWM_WINDOW_PADDING") + .ok() + .and_then(|s| s.parse().ok()) + .unwrap_or(4) +} + /// Port of `ewm_sdl_green`: full green packed for the renderer's format. pub fn green(canvas: &WindowCanvas) -> u32 { match pixel_format(canvas) { diff --git a/ewm/src/two.rs b/ewm/src/two.rs index 390008c..4b71618 100644 --- a/ewm/src/two.rs +++ b/ewm/src/two.rs @@ -620,6 +620,7 @@ pub fn main(args: &[String]) -> i32 { Err(code) => return code, }; let fps = options.fps; + let pad = sdl::window_padding(); // Initialize SDL @@ -635,7 +636,7 @@ pub fn main(args: &[String]) -> i32 { let controller_subsystem = context.gamepad().ok(); let window = video - .window("EWM v0.1 / Apple ][+", 280 * 3, 192 * 3) + .window("EWM v0.1 / Apple ][+", 280 * 3 + 2 * pad, 192 * 3 + 2 * pad) .position(400, 60) .build(); let window = match window { @@ -653,10 +654,12 @@ pub fn main(args: &[String]) -> i32 { return 1; } + // Logical units are window pixels: the screen texture is drawn at 3x + // into an explicit rect, leaving pad window pixels around it. canvas .set_logical_size( - SCR_WIDTH as u32, - SCR_HEIGHT as u32, + SCR_WIDTH as u32 * 3 + 2 * pad, + SCR_HEIGHT as u32 * 3 + 2 * pad, SDL_RendererLogicalPresentation::LETTERBOX, ) .expect("Failed to set logical size"); @@ -855,21 +858,15 @@ pub fn main(args: &[String]) -> i32 { } else { 0 }; - let _ = canvas - .window_mut() - .set_size(SCR_WIDTH as u32 * 3, SCR_HEIGHT as u32 * 3 + extra); + let _ = canvas.window_mut().set_size( + SCR_WIDTH as u32 * 3 + 2 * pad, + SCR_HEIGHT as u32 * 3 + 2 * pad + extra, + ); let _ = canvas.set_logical_size( - SCR_WIDTH as u32 * 3, - SCR_HEIGHT as u32 * 3 + extra, + SCR_WIDTH as u32 * 3 + 2 * pad, + SCR_HEIGHT as u32 * 3 + 2 * pad + extra, SDL_RendererLogicalPresentation::LETTERBOX, ); - if !status_bar_visible { - let _ = canvas.set_logical_size( - SCR_WIDTH as u32, - SCR_HEIGHT as u32, - SDL_RendererLogicalPresentation::LETTERBOX, - ); - } } Keycode::P => paused = !paused, _ => {} @@ -952,8 +949,14 @@ pub fn main(args: &[String]) -> i32 { texture .update(None, &pixels_to_bytes(&scr.pixels), SCR_WIDTH * 4) .expect("Failed to update texture"); + let screen_dst = Rect::new( + pad as i32, + pad as i32, + SCR_WIDTH as u32 * 3, + SCR_HEIGHT as u32 * 3, + ); canvas - .copy(&texture, None, None) + .copy(&texture, None, screen_dst) .expect("Failed to copy texture"); if status_bar_visible { @@ -962,8 +965,8 @@ pub fn main(args: &[String]) -> i32 { .update(None, &pixels_to_bytes(&bar), TTY_PIXEL_WIDTH * 4) .expect("Failed to update bar texture"); let dst = Rect::new( - 0, - SCR_HEIGHT as i32 * 3, + pad as i32, + pad as i32 + SCR_HEIGHT as i32 * 3, SCR_WIDTH as u32 * 3, STATUS_BAR_HEIGHT * 3, ); @@ -989,7 +992,7 @@ pub fn main(args: &[String]) -> i32 { TTY_PIXEL_WIDTH * 4, ) .expect("Failed to update tty texture"); - let _ = canvas.copy(&tty_texture, None, None); + let _ = canvas.copy(&tty_texture, None, screen_dst); } canvas.present();