winbats transp

This commit is contained in:
jess 2026-04-23 09:05:41 -07:00
parent 3a59cc5ab6
commit c234ae5308
1 changed files with 82 additions and 9 deletions

View File

@ -1,7 +1,7 @@
#![cfg_attr(all(target_os = "windows", not(debug_assertions)), windows_subsystem = "windows")] #![cfg_attr(all(target_os = "windows", not(debug_assertions)), windows_subsystem = "windows")]
use std::num::NonZeroU32;
use std::path::PathBuf; use std::path::PathBuf;
use std::time::Instant;
use layers::ffi::ViewportHandle; use layers::ffi::ViewportHandle;
use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
@ -14,6 +14,7 @@ use winit::window::{Window, WindowAttributes, WindowId, WindowLevel};
const DEFAULT_LOGICAL_SIZE: (u32, u32) = (480, 640); const DEFAULT_LOGICAL_SIZE: (u32, u32) = (480, 640);
const MIN_LOGICAL_SIZE: (u32, u32) = (380, 220); const MIN_LOGICAL_SIZE: (u32, u32) = (380, 220);
const ALPHA_FADE_MS: u128 = 150;
fn main() { fn main() {
let plugin_root = discover_plugin_root(); let plugin_root = discover_plugin_root();
@ -45,7 +46,6 @@ fn run() {
} }
} }
#[derive(Default)]
struct ShellApp { struct ShellApp {
window: Option<Box<Window>>, window: Option<Box<Window>>,
handle: Option<ViewportHandle>, handle: Option<ViewportHandle>,
@ -53,6 +53,27 @@ struct ShellApp {
is_hovered: bool, is_hovered: bool,
modifiers: ModifiersState, modifiers: ModifiersState,
last_cursor: PhysicalPosition<f64>, last_cursor: PhysicalPosition<f64>,
current_alpha: f32,
target_alpha: f32,
tween_from: f32,
tween_started: Option<Instant>,
}
impl Default for ShellApp {
fn default() -> Self {
Self {
window: None,
handle: None,
is_focused: false,
is_hovered: false,
modifiers: ModifiersState::empty(),
last_cursor: PhysicalPosition::new(0.0, 0.0),
current_alpha: 1.0,
target_alpha: 1.0,
tween_from: 1.0,
tween_started: None,
}
}
} }
impl ApplicationHandler for ShellApp { impl ApplicationHandler for ShellApp {
@ -61,7 +82,6 @@ impl ApplicationHandler for ShellApp {
return; return;
} }
tracing::info!("resumed: creating window"); tracing::info!("resumed: creating window");
let colors = layers::ui::colors::get();
let attrs = WindowAttributes::default() let attrs = WindowAttributes::default()
.with_title("Layers") .with_title("Layers")
.with_inner_size(LogicalSize::new(DEFAULT_LOGICAL_SIZE.0, DEFAULT_LOGICAL_SIZE.1)) .with_inner_size(LogicalSize::new(DEFAULT_LOGICAL_SIZE.0, DEFAULT_LOGICAL_SIZE.1))
@ -84,6 +104,7 @@ impl ApplicationHandler for ShellApp {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
apply_win11_chrome(&raw_window); apply_win11_chrome(&raw_window);
set_window_alpha(&window, self.current_alpha);
let raw_display = window let raw_display = window
.display_handle() .display_handle()
.expect("winit: display handle") .expect("winit: display handle")
@ -113,7 +134,7 @@ impl ApplicationHandler for ShellApp {
self.window = Some(window); self.window = Some(window);
self.handle = Some(handle); self.handle = Some(handle);
self.apply_window_alpha(colors); self.refresh_target_alpha();
} }
fn window_event( fn window_event(
@ -146,14 +167,17 @@ impl ApplicationHandler for ShellApp {
} }
WindowEvent::Focused(focused) => { WindowEvent::Focused(focused) => {
self.is_focused = focused; self.is_focused = focused;
self.refresh_target_alpha();
} }
WindowEvent::CursorEntered { .. } => { WindowEvent::CursorEntered { .. } => {
self.is_hovered = true; self.is_hovered = true;
self.refresh_target_alpha();
} }
WindowEvent::CursorLeft { .. } => { WindowEvent::CursorLeft { .. } => {
self.is_hovered = false; self.is_hovered = false;
handle.push_mouse_left(); handle.push_mouse_left();
window.request_redraw(); window.request_redraw();
self.refresh_target_alpha();
} }
WindowEvent::CursorMoved { position, .. } => { WindowEvent::CursorMoved { position, .. } => {
self.last_cursor = position; self.last_cursor = position;
@ -211,6 +235,7 @@ impl ApplicationHandler for ShellApp {
} }
fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) { fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
self.step_alpha_tween();
if let Some(window) = self.window.as_ref() { if let Some(window) = self.window.as_ref() {
window.request_redraw(); window.request_redraw();
} }
@ -218,17 +243,38 @@ impl ApplicationHandler for ShellApp {
} }
impl ShellApp { impl ShellApp {
fn apply_window_alpha(&self, colors: &layers::ui::colors::Colors) { fn refresh_target_alpha(&mut self) {
let Some(_window) = self.window.as_ref() else { return; }; let colors = layers::ui::colors::get();
let alpha = if self.is_focused && self.is_hovered { let target = if self.is_focused && self.is_hovered {
colors.window.alpha_focused_hovered colors.window.alpha_focused_hovered
} else if self.is_focused || self.is_hovered { } else if self.is_focused || self.is_hovered {
colors.window.alpha_partial colors.window.alpha_partial
} else { } else {
colors.window.alpha_idle colors.window.alpha_idle
}; };
let _ = alpha; if (target - self.target_alpha).abs() < 0.001 {
let _ = NonZeroU32::new(1); return;
}
self.tween_from = self.current_alpha;
self.target_alpha = target;
self.tween_started = Some(Instant::now());
}
fn step_alpha_tween(&mut self) {
let Some(started) = self.tween_started else { return; };
let Some(window) = self.window.as_ref() else { return; };
let prev = self.current_alpha;
let elapsed = started.elapsed().as_millis();
if elapsed >= ALPHA_FADE_MS {
self.current_alpha = self.target_alpha;
self.tween_started = None;
} else {
let t = elapsed as f32 / ALPHA_FADE_MS as f32;
self.current_alpha = self.tween_from + (self.target_alpha - self.tween_from) * t;
}
if (self.current_alpha - prev).abs() > 0.001 || self.tween_started.is_none() {
set_window_alpha(window, self.current_alpha);
}
} }
} }
@ -258,6 +304,33 @@ fn encode_modifiers(mods: ModifiersState) -> u32 {
bits bits
} }
#[cfg(target_os = "windows")]
fn set_window_alpha(window: &Window, alpha: f32) {
use raw_window_handle::RawWindowHandle;
use windows::Win32::Foundation::{COLORREF, HWND};
use windows::Win32::UI::WindowsAndMessaging::{
GetWindowLongPtrW, SetLayeredWindowAttributes, SetWindowLongPtrW,
GWL_EXSTYLE, LWA_ALPHA, WS_EX_LAYERED,
};
let Ok(handle) = window.window_handle() else { return; };
let RawWindowHandle::Win32(win32) = handle.as_raw() else { return; };
let hwnd = HWND(win32.hwnd.get() as *mut _);
let a = (alpha.clamp(0.0, 1.0) * 255.0).round() as u8;
unsafe {
let ex = GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
let layered = WS_EX_LAYERED.0 as isize;
if ex & layered == 0 {
SetWindowLongPtrW(hwnd, GWL_EXSTYLE, ex | layered);
}
let _ = SetLayeredWindowAttributes(hwnd, COLORREF(0), a, LWA_ALPHA);
}
}
#[cfg(not(target_os = "windows"))]
fn set_window_alpha(_window: &Window, _alpha: f32) {}
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
fn apply_win11_chrome(raw_window: &raw_window_handle::RawWindowHandle) { fn apply_win11_chrome(raw_window: &raw_window_handle::RawWindowHandle) {
use raw_window_handle::RawWindowHandle; use raw_window_handle::RawWindowHandle;