diff --git a/Cargo.lock b/Cargo.lock index b306124..9997d56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -559,6 +559,7 @@ dependencies = [ "arboard", "fontdue", "rdev", + "send_wrapper", "softbuffer", "tiny-skia", "winit", @@ -616,6 +617,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + [[package]] name = "gethostname" version = "0.4.3" @@ -1166,6 +1173,15 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" +dependencies = [ + "futures-core", +] + [[package]] name = "serde" version = "1.0.198" diff --git a/Cargo.toml b/Cargo.toml index a467588..231c11e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,5 @@ winit = "0.29.15" tiny-skia = "0.11.4" softbuffer = "0.4.2" rdev = "0.5.3" -fontdue = "0.8.0" \ No newline at end of file +fontdue = "0.8.0" +send_wrapper = { version = "0.6.0", features = ["futures"] } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index ad6cac4..af658e5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,24 +1,34 @@ +use std::collections::HashMap; use std::iter::Zip; use std::num::NonZeroU32; +use std::ops::Deref; +use std::os::linux::raw::stat; +use send_wrapper::SendWrapper; +use std::sync::mpsc::channel; use fontdue::Font; -use tiny_skia::{Color, FillRule, Paint, PathBuilder, Pixmap, Stroke, Transform}; +use tiny_skia::{Color, ColorU8, FillRule, Paint, PathBuilder, Pixmap, Rect, Stroke, Transform}; use softbuffer::{Context, Surface}; use arboard::{Clipboard, ImageData}; use winit::event::{ElementState, Event, KeyEvent, MouseButton, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder}; use winit::platform::x11::EventLoopBuilderExtX11; -use winit::window::{WindowBuilder, WindowButtons, WindowLevel}; -use winit::dpi::PhysicalPosition; +use winit::window::{Window, WindowBuilder, WindowButtons, WindowId, WindowLevel}; +use winit::dpi::{PhysicalPosition, PhysicalSize}; use winit::window::CursorIcon; use winit::window::ResizeDirection; +use winit::dpi::LogicalSize; use rdev::*; use std::thread; -use std::sync::{Arc,Mutex}; -use std::borrow::Cow; +use std::sync::{Arc,Mutex,MutexGuard}; +use std::borrow::{BorrowMut, Cow}; +use std::cell::{Cell, Ref}; +use std::cell::{RefCell, RefMut}; +use std::rc::Rc; +use core::slice::IterMut; enum ClipboardContent<'a> { Image(Cow<'a, [u8]>), @@ -42,7 +52,7 @@ fn get_clipboard(clipboard: &mut Clipboard) -> ClipboardContent { } } -fn render_text(text: String, size: f32, font: Font) -> Pixmap { +fn render_text(text: String, size: f32, font: Font, color: Color) -> Pixmap { let mut chars: Vec<((usize, usize), Vec)> = Vec::new(); for ele in text.chars() { let (metrics, bitmap) = font.rasterize(ele, size); @@ -67,9 +77,203 @@ fn render_text(text: String, size: f32, font: Font) -> Pixmap { pixmap } -fn popup_clipboard(content: ClipboardContent) { - let event_loop = EventLoopBuilder::new().with_any_thread(true).build().unwrap(); - let window = WindowBuilder::new() +pub trait RemoveElem { + fn remove_elem(&mut self, predicate: F) -> Option + where F: Fn(&T) -> bool; + + fn remove_value(&mut self, value: &T) -> Option; +} + +impl RemoveElem for Vec { + fn remove_elem(&mut self, predicate: F) -> Option + where + F: Fn(&T) -> bool, + { + self.iter() + .position(predicate) + .map(|index| self.remove(index)) + } + + fn remove_value(&mut self, value: &T) -> Option { + self.remove_elem(|e|{e == value}) + } +} + +struct Note { + window: Arc, + window_id: WindowId, + context: Context>, + surface: Surface, Arc>, + mouse_pos: PhysicalPosition +} + +impl PartialEq for Note { + fn eq(&self, other: &Self) -> bool { + self.window_id == other.window_id + } +} + +impl Note { + fn new(window: Window) -> Self { + let arc_window = Arc::new(window); + + let context = Context::new(arc_window.clone()).unwrap(); + let mut surface = Surface::new(&context, arc_window.clone()).unwrap(); + + let mouse_pos: PhysicalPosition = PhysicalPosition::new(0.0, 0.0); + + let window_id = arc_window.clone().id(); + + Note { + window: arc_window.clone(), + window_id, + context, + surface, + mouse_pos + } + } +} + +fn create_event_loop() -> EventLoop { + let event_loop: EventLoop = EventLoopBuilder::with_user_event().with_any_thread(true).build().unwrap(); + + event_loop.set_control_flow(ControlFlow::Poll); + event_loop.set_control_flow(ControlFlow::Wait); + + event_loop +} + +fn get_window<'a>(mut windows: IterMut<'a, Note>, id: WindowId) -> Option<&'a mut Note> { + for note in windows { + if note.window_id == id { + return Some(note); + } + } + + None +} + +fn run_event_loop<'a>(event_loop: EventLoop, windows: RefCell>) { + event_loop.run(move |event, elwt| { + let mut windows_local = windows.borrow_mut(); + + match event { + Event::Resumed => {}, + Event::UserEvent(win) => { + let mut built = win.build(&elwt).unwrap(); + let mut win = Note::new(built); + windows_local.push(win); + }, + Event::WindowEvent { window_id, event } => { + let mut win = get_window(windows_local.iter_mut(), window_id).unwrap(); + + match event { + WindowEvent::MouseInput { device_id, state, button } => { + // dbg!((device_id, state, button)); + + let (width, height) = { + let size = win.window.inner_size(); + (size.width as f64, size.height as f64) + }; + + if button == MouseButton::Left && state.is_pressed() { + if win.mouse_pos.x > width - 30.0 && win.mouse_pos.y < 30.0 { // close button + win.window.set_visible(false); + windows_local.remove_elem(|e| e.window_id == window_id); + } else if win.mouse_pos.x < 20.0 && win.mouse_pos.y < 20.0 { // west north + win.window.drag_resize_window(ResizeDirection::NorthWest).unwrap(); + } else if win.mouse_pos.x < 20.0 && win.mouse_pos.y > height - 20.0 { // west south + win.window.drag_resize_window(ResizeDirection::SouthWest).unwrap(); + } else if win.mouse_pos.x > width - 20.0 && win.mouse_pos.y < 20.0 { // east north + win.window.drag_resize_window(ResizeDirection::NorthEast).unwrap(); + } else if win.mouse_pos.x > width - 20.0 && win.mouse_pos.y > height - 20.0 { // east south + win.window.drag_resize_window(ResizeDirection::SouthEast).unwrap(); + } else if win.mouse_pos.y < 20.0 && win.mouse_pos.x < 20.0 { // north west + win.window.drag_resize_window(ResizeDirection::NorthWest).unwrap(); + } else if win.mouse_pos.y < 20.0 && win.mouse_pos.x > width - 20.0 { // north east + win.window.drag_resize_window(ResizeDirection::NorthEast).unwrap(); + } else if win.mouse_pos.y > height - 20.0 && win.mouse_pos.x < 20.0 { // south west + win.window.drag_resize_window(ResizeDirection::SouthWest).unwrap(); + } else if win.mouse_pos.y > height - 20.0 && win.mouse_pos.x > width - 20.0 { // south east + win.window.drag_resize_window(ResizeDirection::SouthEast).unwrap(); + } else if win.mouse_pos.x < 20.0 { // west + win.window.drag_resize_window(ResizeDirection::West).unwrap(); + } else if win.mouse_pos.x > width - 20.0 { // east + win.window.drag_resize_window(ResizeDirection::East).unwrap(); + } else if win.mouse_pos.y > height - 20.0 { // south + win.window.drag_resize_window(ResizeDirection::South).unwrap(); + } else if win.mouse_pos.y < 20.0 { // north + win.window.drag_resize_window(ResizeDirection::North).unwrap(); + } else { // else + win.window.drag_window(); + } + } + }, + WindowEvent::CursorMoved { device_id, position } => { + win.mouse_pos = position; + + let (width, height) = { + let size = win.window.inner_size(); + (size.width as f64, size.height as f64) + }; + + if position.x > width - 30.0 && position.y < 30.0 { + win.window.set_cursor_icon(CursorIcon::Pointer); + } else if position.x < 20.0 || position.x > width - 20.0 { + win.window.set_cursor_icon(CursorIcon::EwResize) + } else if position.y < 20.0 || position.y > height - 20.0 { + win.window.set_cursor_icon(CursorIcon::NsResize) + } else { + win.window.set_cursor_icon(CursorIcon::Pointer); + } + }, + WindowEvent::RedrawRequested => { + let (width, height) = { + let size = win.window.inner_size(); + (size.width, size.height) + }; + win.surface + .resize( + NonZeroU32::new(width).unwrap(), + NonZeroU32::new(height).unwrap(), + ) + .unwrap(); + + let mut pixmap = Pixmap::new(width, height).unwrap(); // берем + pixmap.fill(Color::WHITE); + + let path = PathBuilder::from_rect(Rect::from_xywh(width as f32 - 30.0, 0.0, 30.0, 30.0).unwrap()); + + let mut paint = Paint::default(); + paint.set_color_rgba8(220, 80, 80, 150); + + pixmap.fill_path( + &path, + &paint, + FillRule::EvenOdd, + Transform::identity(), + None, + ); + + let mut buffer = win.surface.buffer_mut().unwrap(); + for index in 0..(width * height) as usize { + buffer[index] = pixmap.data()[index * 4 + 2] as u32 + | (pixmap.data()[index * 4 + 1] as u32) << 8 + | (pixmap.data()[index * 4] as u32) << 16; + } + + buffer.present().unwrap(); + }, + _ => (), + } + }, + _ => (), + } + }).unwrap(); +} + +fn popup_clipboard(content: ClipboardContent) -> WindowBuilder { + WindowBuilder::new() .with_enabled_buttons(WindowButtons::empty()) .with_decorations(false) .with_window_level(WindowLevel::AlwaysOnTop) @@ -78,142 +282,40 @@ fn popup_clipboard(content: ClipboardContent) { ClipboardContent::Text(_) => "Text", _ => "???" })) - .with_inner_size(winit::dpi::LogicalSize::new(800.0, 600.0)) + .with_inner_size(LogicalSize::new(800.0, 600.0)) .with_resizable(true) .with_visible(true) - .with_min_inner_size(winit::dpi::LogicalSize::new(50.0, 50.0)) - // .with_resize_increments((0,0)) - .build(&event_loop).unwrap(); - - event_loop.set_control_flow(ControlFlow::Poll); - event_loop.set_control_flow(ControlFlow::Wait); - - let context = Context::new(&window).unwrap(); - let mut surface = Surface::new(&context, &window).unwrap(); - - let mut mouse_pos = PhysicalPosition::new(0.0, 0.0); - - event_loop.run(|event, elwt| { - match event { - Event::Resumed => {}, - Event::WindowEvent { window_id, event } => match event { - WindowEvent::CloseRequested => { - elwt.exit(); - }, - WindowEvent::MouseInput { device_id, state, button } => { - // dbg!((device_id, state, button)); - - let (width, height) = { - let size = window.inner_size(); - (size.width as f64, size.height as f64) - }; - - if button == MouseButton::Left && state.is_pressed() { - if mouse_pos.x > width - 30.0 && mouse_pos.y < 30.0 { // close button - elwt.exit(); - } else if mouse_pos.x < 20.0 && mouse_pos.y < 20.0 { // west north - window.drag_resize_window(ResizeDirection::NorthWest).unwrap(); - } else if mouse_pos.x < 20.0 && mouse_pos.y > height - 20.0 { // west south - window.drag_resize_window(ResizeDirection::SouthWest).unwrap(); - } else if mouse_pos.x > width - 20.0 && mouse_pos.y < 20.0 { // east north - window.drag_resize_window(ResizeDirection::NorthEast).unwrap(); - } else if mouse_pos.x > width - 20.0 && mouse_pos.y > height - 20.0 { // east south - window.drag_resize_window(ResizeDirection::SouthEast).unwrap(); - } else if mouse_pos.y < 20.0 && mouse_pos.x < 20.0 { // north west - window.drag_resize_window(ResizeDirection::NorthWest).unwrap(); - } else if mouse_pos.y < 20.0 && mouse_pos.x > width - 20.0 { // north east - window.drag_resize_window(ResizeDirection::NorthEast).unwrap(); - } else if mouse_pos.y > height - 20.0 && mouse_pos.x < 20.0 { // south west - window.drag_resize_window(ResizeDirection::SouthWest).unwrap(); - } else if mouse_pos.y > height - 20.0 && mouse_pos.x > width - 20.0 { // south east - window.drag_resize_window(ResizeDirection::SouthEast).unwrap(); - } else if mouse_pos.x < 20.0 { // west - window.drag_resize_window(ResizeDirection::West).unwrap(); - } else if mouse_pos.x > width - 20.0 { // east - window.drag_resize_window(ResizeDirection::East).unwrap(); - } else if mouse_pos.y > height - 20.0 { // south - window.drag_resize_window(ResizeDirection::South).unwrap(); - } else if mouse_pos.y < 20.0 { // north - window.drag_resize_window(ResizeDirection::North).unwrap(); - } else { // else - window.drag_window(); - } - } - }, - WindowEvent::CursorMoved { device_id, position } => { - mouse_pos = position; - - let (width, height) = { - let size = window.inner_size(); - (size.width as f64, size.height as f64) - }; - - if position.x > width - 30.0 && position.y < 30.0 { - window.set_cursor_icon(CursorIcon::Pointer); - } else if position.x < 20.0 || position.x > width - 20.0 { - window.set_cursor_icon(CursorIcon::EwResize) - } else if position.y < 20.0 || position.y > height - 20.0 { - window.set_cursor_icon(CursorIcon::NsResize) - } else { - window.set_cursor_icon(CursorIcon::Pointer); - } - }, - WindowEvent::RedrawRequested => { - let (width, height) = { // объявляем переменные - let size = window.inner_size(); // берем размер - (size.width, size.height) // засовываем размер в тупл и выводим в переменные - }; - surface - .resize( // изменение размера сурфейса - NonZeroU32::new(width).unwrap(), - NonZeroU32::new(height).unwrap(), - ) - .unwrap(); - - let mut pixmap = Pixmap::new(width, height).unwrap(); // берем - pixmap.fill(Color::WHITE); - - - - let mut buffer = surface.buffer_mut().unwrap(); - for index in 0..(width * height) as usize { - buffer[index] = pixmap.data()[index * 4 + 2] as u32 - | (pixmap.data()[index * 4 + 1] as u32) << 8 - | (pixmap.data()[index * 4] as u32) << 16; - } - - buffer.present().unwrap(); - }, - _ => (), - }, - _ => (), - } - }).unwrap(); - - window.set_visible(false); + .with_min_inner_size(LogicalSize::new(50.0, 50.0)) } fn main() { - let mut pressed: Vec = Vec::new(); - let mut clipboard = Arc::new(Mutex::new(Clipboard::new().unwrap())); + let event_loop = create_event_loop(); + let windows = RefCell::new(Vec::new()); - listen(move |event: rdev::Event| { - if let EventType::KeyPress(key) = event.event_type { - if !pressed.contains(&key) { - pressed.push(key); - } + let event_loop_proxy = event_loop.create_proxy(); - if key == Key::KeyN && - pressed.contains(&Key::ControlLeft) && - pressed.contains(&Key::Alt) { - let mut clipboard_now = clipboard.clone(); - thread::spawn(move || { popup_clipboard(get_clipboard(&mut clipboard_now.lock().unwrap())) }); - } - } else if let EventType::KeyRelease(key) = event.event_type { - if pressed.contains(&key) { - pressed.remove(pressed.iter().position(|x| *x == key).unwrap()); - } - } + thread::spawn(move || { + let mut pressed: Vec = Vec::new(); + let mut clipboard = Clipboard::new().unwrap(); - }).unwrap(); + listen(move |event: rdev::Event| { + if let EventType::KeyPress(key) = event.event_type { + if !pressed.contains(&key) { + pressed.push(key); + } + + if key == Key::KeyN && + pressed.contains(&Key::ControlLeft) && + pressed.contains(&Key::Alt) { + event_loop_proxy.send_event(popup_clipboard(get_clipboard(&mut clipboard))).unwrap(); + } + } else if let EventType::KeyRelease(key) = event.event_type { + if pressed.contains(&key) { + pressed.remove(pressed.iter().position(|x| *x == key).unwrap()); + } + } + }); + }); + + run_event_loop(event_loop, windows); }