use crate::event::Event;
use crate::render::adapter::{AdapterBase, PIXEL_SYM_HEIGHT, PIXEL_SYM_WIDTH};
use std::sync::Arc;
use winit::{
event::{Event as WinitEvent, WindowEvent},
window::{CustomCursor, Window},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BorderArea {
None,
Close,
TopBar,
Other,
}
pub fn check_border_area(x: f64, y: f64, base: &AdapterBase) -> BorderArea {
let w = base.gr.cell_width() as f64;
let h = base.gr.cell_height() as f64;
let sw = (base.cell_w + 2) as f64;
if y >= 0.0 && y < h {
if x >= 0.0 && x <= (sw - 1.0) * w {
return BorderArea::TopBar;
}
if x > (sw - 1.0) * w && x <= sw * w {
return BorderArea::Close;
}
} else if x > w && x <= (sw - 1.0) * w {
return BorderArea::None;
}
BorderArea::Other
}
pub fn load_custom_cursor(
event_loop: &winit::event_loop::EventLoop<()>,
) -> Option<CustomCursor> {
let project_path = &crate::get_game_config().project_path;
let cursor_path = format!(
"{}{}{}",
project_path,
std::path::MAIN_SEPARATOR,
"assets/pix/cursor.png"
);
if let Ok(cursor_img) = image::open(&cursor_path) {
let cursor_rgba = cursor_img.to_rgba8();
let (width, height) = cursor_rgba.dimensions();
let mut cursor_data = cursor_rgba.into_raw();
for chunk in cursor_data.chunks_exact_mut(4) {
let alpha = chunk[3] as f32 / 255.0;
chunk[0] = (chunk[0] as f32 * alpha) as u8; chunk[1] = (chunk[1] as f32 * alpha) as u8; chunk[2] = (chunk[2] as f32 * alpha) as u8; }
match CustomCursor::from_rgba(cursor_data, width as u16, height as u16, 0, 0) {
Ok(cursor_source) => {
return Some(event_loop.create_custom_cursor(cursor_source));
}
Err(e) => {
log::warn!("Failed to create cursor source: {:?}", e);
}
}
} else {
log::warn!("Cursor image not found: {}", cursor_path);
}
None
}
pub fn apply_cursor_to_window(window: &Arc<Window>, cursor: &CustomCursor) {
window.set_cursor(cursor.clone());
window.set_cursor_visible(true);
}
#[derive(Default)]
pub struct Drag {
pub need: bool,
pub draging: bool,
pub mouse_x: f64,
pub mouse_y: f64,
pub dx: f64,
pub dy: f64,
}
#[derive(Debug, Clone)]
pub struct WindowInitParams {
pub width: u16,
pub height: u16,
pub ratio_x: f32,
pub ratio_y: f32,
pub title: String,
pub texture_path: String,
}
pub fn winit_move_win(drag_need: &mut bool, window: Option<&Window>, dx: f64, dy: f64) {
if *drag_need {
if let Some(win) = window {
if let Ok(pos) = win.outer_position() {
let new_x = pos.x + dx as i32;
let new_y = pos.y + dy as i32;
win.set_outer_position(winit::dpi::PhysicalPosition::new(new_x, new_y));
}
}
*drag_need = false;
}
}
pub fn input_events_from_winit(
event: &WinitEvent<()>,
adjx: f32,
adjy: f32,
use_tui_height: bool,
cursor_pos: &mut (f64, f64),
) -> Option<Event> {
use crate::event::{
Event, KeyCode, KeyEvent, KeyModifiers, MouseButton::*, MouseEvent, MouseEventKind::*,
};
let sym_width = PIXEL_SYM_WIDTH.get().expect("lazylock init");
let sym_height = PIXEL_SYM_HEIGHT.get().expect("lazylock init");
if let WinitEvent::WindowEvent {
event: window_event,
..
} = event {
match window_event {
WindowEvent::KeyboardInput {
event: key_event, ..
} => {
if key_event.state == winit::event::ElementState::Pressed {
if let winit::keyboard::PhysicalKey::Code(keycode) = key_event.physical_key
{
let kc = match keycode {
winit::keyboard::KeyCode::Space => ' ',
winit::keyboard::KeyCode::KeyA => 'a',
winit::keyboard::KeyCode::KeyB => 'b',
winit::keyboard::KeyCode::KeyC => 'c',
winit::keyboard::KeyCode::KeyD => 'd',
winit::keyboard::KeyCode::KeyE => 'e',
winit::keyboard::KeyCode::KeyF => 'f',
winit::keyboard::KeyCode::KeyG => 'g',
winit::keyboard::KeyCode::KeyH => 'h',
winit::keyboard::KeyCode::KeyI => 'i',
winit::keyboard::KeyCode::KeyJ => 'j',
winit::keyboard::KeyCode::KeyK => 'k',
winit::keyboard::KeyCode::KeyL => 'l',
winit::keyboard::KeyCode::KeyM => 'm',
winit::keyboard::KeyCode::KeyN => 'n',
winit::keyboard::KeyCode::KeyO => 'o',
winit::keyboard::KeyCode::KeyP => 'p',
winit::keyboard::KeyCode::KeyQ => 'q',
winit::keyboard::KeyCode::KeyR => 'r',
winit::keyboard::KeyCode::KeyS => 's',
winit::keyboard::KeyCode::KeyT => 't',
winit::keyboard::KeyCode::KeyU => 'u',
winit::keyboard::KeyCode::KeyV => 'v',
winit::keyboard::KeyCode::KeyW => 'w',
winit::keyboard::KeyCode::KeyX => 'x',
winit::keyboard::KeyCode::KeyY => 'y',
winit::keyboard::KeyCode::KeyZ => 'z',
winit::keyboard::KeyCode::ArrowUp => {
return Some(Event::Key(KeyEvent::new(
KeyCode::Up,
KeyModifiers::NONE,
)))
}
winit::keyboard::KeyCode::ArrowDown => {
return Some(Event::Key(KeyEvent::new(
KeyCode::Down,
KeyModifiers::NONE,
)))
}
winit::keyboard::KeyCode::ArrowLeft => {
return Some(Event::Key(KeyEvent::new(
KeyCode::Left,
KeyModifiers::NONE,
)))
}
winit::keyboard::KeyCode::ArrowRight => {
return Some(Event::Key(KeyEvent::new(
KeyCode::Right,
KeyModifiers::NONE,
)))
}
winit::keyboard::KeyCode::Enter => {
return Some(Event::Key(KeyEvent::new(
KeyCode::Enter,
KeyModifiers::NONE,
)))
}
winit::keyboard::KeyCode::Escape => {
return Some(Event::Key(KeyEvent::new(
KeyCode::Esc,
KeyModifiers::NONE,
)))
}
winit::keyboard::KeyCode::Backspace => {
return Some(Event::Key(KeyEvent::new(
KeyCode::Backspace,
KeyModifiers::NONE,
)))
}
winit::keyboard::KeyCode::Tab => {
return Some(Event::Key(KeyEvent::new(
KeyCode::Tab,
KeyModifiers::NONE,
)))
}
winit::keyboard::KeyCode::Delete => {
return Some(Event::Key(KeyEvent::new(
KeyCode::Delete,
KeyModifiers::NONE,
)))
}
winit::keyboard::KeyCode::Home => {
return Some(Event::Key(KeyEvent::new(
KeyCode::Home,
KeyModifiers::NONE,
)))
}
winit::keyboard::KeyCode::End => {
return Some(Event::Key(KeyEvent::new(
KeyCode::End,
KeyModifiers::NONE,
)))
}
winit::keyboard::KeyCode::PageUp => {
return Some(Event::Key(KeyEvent::new(
KeyCode::PageUp,
KeyModifiers::NONE,
)))
}
winit::keyboard::KeyCode::PageDown => {
return Some(Event::Key(KeyEvent::new(
KeyCode::PageDown,
KeyModifiers::NONE,
)))
}
winit::keyboard::KeyCode::Insert => {
return Some(Event::Key(KeyEvent::new(
KeyCode::Insert,
KeyModifiers::NONE,
)))
}
winit::keyboard::KeyCode::Digit1 => '1',
winit::keyboard::KeyCode::Digit2 => '2',
winit::keyboard::KeyCode::Digit3 => '3',
winit::keyboard::KeyCode::Digit4 => '4',
winit::keyboard::KeyCode::Digit5 => '5',
winit::keyboard::KeyCode::Digit6 => '6',
winit::keyboard::KeyCode::Digit7 => '7',
winit::keyboard::KeyCode::Digit8 => '8',
winit::keyboard::KeyCode::Digit9 => '9',
winit::keyboard::KeyCode::Digit0 => '0',
_ => return None,
};
return Some(Event::Key(KeyEvent::new(
KeyCode::Char(kc),
KeyModifiers::NONE,
)));
}
}
}
WindowEvent::CursorMoved { position, .. } => {
cursor_pos.0 = position.x;
cursor_pos.1 = position.y;
let cell_height = if use_tui_height {
*sym_height * 2.0
} else {
*sym_height
};
let px = (cursor_pos.0 / (*sym_width as f64 / adjx as f64)) as u16;
let py = (cursor_pos.1 / (cell_height as f64 / adjy as f64)) as u16;
return Some(Event::Mouse(MouseEvent {
kind: Moved,
column: px,
row: py,
modifiers: KeyModifiers::NONE,
}));
}
WindowEvent::MouseInput { state, button, .. } => {
let cell_height = if use_tui_height {
*sym_height * 2.0
} else {
*sym_height
};
if *state == winit::event::ElementState::Pressed {
let px = (cursor_pos.0 / (*sym_width as f64 / adjx as f64)) as u16;
let py = (cursor_pos.1 / (cell_height as f64 / adjy as f64)) as u16;
let mouse_button = match button {
winit::event::MouseButton::Left => Left,
winit::event::MouseButton::Right => Right,
winit::event::MouseButton::Middle => Middle,
_ => Left,
};
return Some(Event::Mouse(MouseEvent {
kind: Down(mouse_button),
column: px,
row: py,
modifiers: KeyModifiers::NONE,
}));
} else {
let px = (cursor_pos.0 / (*sym_width as f64 / adjx as f64)) as u16;
let py = (cursor_pos.1 / (cell_height as f64 / adjy as f64)) as u16;
let mouse_button = match button {
winit::event::MouseButton::Left => Left,
winit::event::MouseButton::Right => Right,
winit::event::MouseButton::Middle => Middle,
_ => Left,
};
return Some(Event::Mouse(MouseEvent {
kind: Up(mouse_button),
column: px,
row: py,
modifiers: KeyModifiers::NONE,
}));
}
}
_ => {}
}
}
None
}
pub fn winit_init_common<T>(
adapter: &mut T,
w: u16,
h: u16,
rx: f32,
ry: f32,
title: String,
) -> (winit::event_loop::EventLoop<()>, WindowInitParams, String)
where
T: crate::render::adapter::Adapter,
{
use crate::render::adapter::{PIXEL_SYM_HEIGHT, PIXEL_SYM_WIDTH};
use log::info;
use winit::event_loop::EventLoop;
info!("Initializing Winit adapter common components...");
let project_path = &crate::get_game_config().project_path;
let layer_data = crate::get_pixel_layer_data().expect("Layer data not loaded");
let texture_path = format!(
"{}{}assets/pix/layered_symbol_map.json",
project_path, std::path::MAIN_SEPARATOR,
);
info!(
"Using layered texture: {} layers ({}x{})",
layer_data.layers.len(), layer_data.layer_size, layer_data.layer_size
);
info!(
"Symbol dimensions: {}x{}",
PIXEL_SYM_WIDTH.get().expect("PIXEL_SYM_WIDTH not initialized"),
PIXEL_SYM_HEIGHT.get().expect("PIXEL_SYM_HEIGHT not initialized"),
);
adapter.set_size(w, h);
adapter.set_title(title.clone());
let base = adapter.get_base();
base.gr.set_ratiox(rx);
base.gr.set_ratioy(ry);
let cell_w = base.cell_w;
let cell_h = base.cell_h;
base.gr.set_pixel_size(cell_w, cell_h);
let event_loop = EventLoop::new().unwrap();
let window_init_params = WindowInitParams {
width: w,
height: h,
ratio_x: rx,
ratio_y: ry,
title,
texture_path: texture_path.clone(),
};
info!("Common initialization completed, window will be created in resumed()");
(event_loop, window_init_params, texture_path)
}