multiple notes nowcargo r

This commit is contained in:
MeexReay 2024-04-24 22:59:47 +03:00
parent 8a8b8b7464
commit 5332385b17
3 changed files with 259 additions and 140 deletions

16
Cargo.lock generated
View File

@ -559,6 +559,7 @@ dependencies = [
"arboard", "arboard",
"fontdue", "fontdue",
"rdev", "rdev",
"send_wrapper",
"softbuffer", "softbuffer",
"tiny-skia", "tiny-skia",
"winit", "winit",
@ -616,6 +617,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
[[package]]
name = "futures-core"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
[[package]] [[package]]
name = "gethostname" name = "gethostname"
version = "0.4.3" version = "0.4.3"
@ -1166,6 +1173,15 @@ dependencies = [
"tiny-skia", "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]] [[package]]
name = "serde" name = "serde"
version = "1.0.198" version = "1.0.198"

View File

@ -12,3 +12,4 @@ tiny-skia = "0.11.4"
softbuffer = "0.4.2" softbuffer = "0.4.2"
rdev = "0.5.3" rdev = "0.5.3"
fontdue = "0.8.0" fontdue = "0.8.0"
send_wrapper = { version = "0.6.0", features = ["futures"] }

View File

@ -1,24 +1,34 @@
use std::collections::HashMap;
use std::iter::Zip; use std::iter::Zip;
use std::num::NonZeroU32; 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 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 softbuffer::{Context, Surface};
use arboard::{Clipboard, ImageData}; use arboard::{Clipboard, ImageData};
use winit::event::{ElementState, Event, KeyEvent, MouseButton, WindowEvent}; use winit::event::{ElementState, Event, KeyEvent, MouseButton, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder}; use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder};
use winit::platform::x11::EventLoopBuilderExtX11; use winit::platform::x11::EventLoopBuilderExtX11;
use winit::window::{WindowBuilder, WindowButtons, WindowLevel}; use winit::window::{Window, WindowBuilder, WindowButtons, WindowId, WindowLevel};
use winit::dpi::PhysicalPosition; use winit::dpi::{PhysicalPosition, PhysicalSize};
use winit::window::CursorIcon; use winit::window::CursorIcon;
use winit::window::ResizeDirection; use winit::window::ResizeDirection;
use winit::dpi::LogicalSize;
use rdev::*; use rdev::*;
use std::thread; use std::thread;
use std::sync::{Arc,Mutex}; use std::sync::{Arc,Mutex,MutexGuard};
use std::borrow::Cow; 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> { enum ClipboardContent<'a> {
Image(Cow<'a, [u8]>), 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<u8>)> = Vec::new(); let mut chars: Vec<((usize, usize), Vec<u8>)> = Vec::new();
for ele in text.chars() { for ele in text.chars() {
let (metrics, bitmap) = font.rasterize(ele, size); let (metrics, bitmap) = font.rasterize(ele, size);
@ -67,104 +77,163 @@ fn render_text(text: String, size: f32, font: Font) -> Pixmap {
pixmap pixmap
} }
fn popup_clipboard(content: ClipboardContent) { pub trait RemoveElem<T: PartialEq> {
let event_loop = EventLoopBuilder::new().with_any_thread(true).build().unwrap(); fn remove_elem<F>(&mut self, predicate: F) -> Option<T>
let window = WindowBuilder::new() where F: Fn(&T) -> bool;
.with_enabled_buttons(WindowButtons::empty())
.with_decorations(false) fn remove_value(&mut self, value: &T) -> Option<T>;
.with_window_level(WindowLevel::AlwaysOnTop) }
.with_title("FONotes - ".to_owned() + (match content {
ClipboardContent::Image(_) => "Image", impl<T: PartialEq> RemoveElem<T> for Vec<T> {
ClipboardContent::Text(_) => "Text", fn remove_elem<F>(&mut self, predicate: F) -> Option<T>
_ => "???" where
})) F: Fn(&T) -> bool,
.with_inner_size(winit::dpi::LogicalSize::new(800.0, 600.0)) {
.with_resizable(true) self.iter()
.with_visible(true) .position(predicate)
.with_min_inner_size(winit::dpi::LogicalSize::new(50.0, 50.0)) .map(|index| self.remove(index))
// .with_resize_increments((0,0)) }
.build(&event_loop).unwrap();
fn remove_value(&mut self, value: &T) -> Option<T> {
self.remove_elem(|e|{e == value})
}
}
struct Note {
window: Arc<Window>,
window_id: WindowId,
context: Context<Arc<Window>>,
surface: Surface<Arc<Window>, Arc<Window>>,
mouse_pos: PhysicalPosition<f64>
}
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<f64> = 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<WindowBuilder> {
let event_loop: EventLoop<WindowBuilder> = EventLoopBuilder::with_user_event().with_any_thread(true).build().unwrap();
event_loop.set_control_flow(ControlFlow::Poll); event_loop.set_control_flow(ControlFlow::Poll);
event_loop.set_control_flow(ControlFlow::Wait); event_loop.set_control_flow(ControlFlow::Wait);
let context = Context::new(&window).unwrap(); event_loop
let mut surface = Surface::new(&context, &window).unwrap(); }
let mut mouse_pos = PhysicalPosition::new(0.0, 0.0); 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<WindowBuilder>, windows: RefCell<Vec<Note>>) {
event_loop.run(move |event, elwt| {
let mut windows_local = windows.borrow_mut();
event_loop.run(|event, elwt| {
match event { match event {
Event::Resumed => {}, Event::Resumed => {},
Event::WindowEvent { window_id, event } => match event { Event::UserEvent(win) => {
WindowEvent::CloseRequested => { let mut built = win.build(&elwt).unwrap();
elwt.exit(); 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 } => { WindowEvent::MouseInput { device_id, state, button } => {
// dbg!((device_id, state, button)); // dbg!((device_id, state, button));
let (width, height) = { let (width, height) = {
let size = window.inner_size(); let size = win.window.inner_size();
(size.width as f64, size.height as f64) (size.width as f64, size.height as f64)
}; };
if button == MouseButton::Left && state.is_pressed() { if button == MouseButton::Left && state.is_pressed() {
if mouse_pos.x > width - 30.0 && mouse_pos.y < 30.0 { // close button if win.mouse_pos.x > width - 30.0 && win.mouse_pos.y < 30.0 { // close button
elwt.exit(); win.window.set_visible(false);
} else if mouse_pos.x < 20.0 && mouse_pos.y < 20.0 { // west north windows_local.remove_elem(|e| e.window_id == window_id);
window.drag_resize_window(ResizeDirection::NorthWest).unwrap(); } else if win.mouse_pos.x < 20.0 && win.mouse_pos.y < 20.0 { // west north
} else if mouse_pos.x < 20.0 && mouse_pos.y > height - 20.0 { // west south win.window.drag_resize_window(ResizeDirection::NorthWest).unwrap();
window.drag_resize_window(ResizeDirection::SouthWest).unwrap(); } else if win.mouse_pos.x < 20.0 && win.mouse_pos.y > height - 20.0 { // west south
} else if mouse_pos.x > width - 20.0 && mouse_pos.y < 20.0 { // east north win.window.drag_resize_window(ResizeDirection::SouthWest).unwrap();
window.drag_resize_window(ResizeDirection::NorthEast).unwrap(); } else if win.mouse_pos.x > width - 20.0 && win.mouse_pos.y < 20.0 { // east north
} else if mouse_pos.x > width - 20.0 && mouse_pos.y > height - 20.0 { // east south win.window.drag_resize_window(ResizeDirection::NorthEast).unwrap();
window.drag_resize_window(ResizeDirection::SouthEast).unwrap(); } else if win.mouse_pos.x > width - 20.0 && win.mouse_pos.y > height - 20.0 { // east south
} else if mouse_pos.y < 20.0 && mouse_pos.x < 20.0 { // north west win.window.drag_resize_window(ResizeDirection::SouthEast).unwrap();
window.drag_resize_window(ResizeDirection::NorthWest).unwrap(); } else if win.mouse_pos.y < 20.0 && win.mouse_pos.x < 20.0 { // north west
} else if mouse_pos.y < 20.0 && mouse_pos.x > width - 20.0 { // north east win.window.drag_resize_window(ResizeDirection::NorthWest).unwrap();
window.drag_resize_window(ResizeDirection::NorthEast).unwrap(); } else if win.mouse_pos.y < 20.0 && win.mouse_pos.x > width - 20.0 { // north east
} else if mouse_pos.y > height - 20.0 && mouse_pos.x < 20.0 { // south west win.window.drag_resize_window(ResizeDirection::NorthEast).unwrap();
window.drag_resize_window(ResizeDirection::SouthWest).unwrap(); } else if win.mouse_pos.y > height - 20.0 && win.mouse_pos.x < 20.0 { // south west
} else if mouse_pos.y > height - 20.0 && mouse_pos.x > width - 20.0 { // south east win.window.drag_resize_window(ResizeDirection::SouthWest).unwrap();
window.drag_resize_window(ResizeDirection::SouthEast).unwrap(); } else if win.mouse_pos.y > height - 20.0 && win.mouse_pos.x > width - 20.0 { // south east
} else if mouse_pos.x < 20.0 { // west win.window.drag_resize_window(ResizeDirection::SouthEast).unwrap();
window.drag_resize_window(ResizeDirection::West).unwrap(); } else if win.mouse_pos.x < 20.0 { // west
} else if mouse_pos.x > width - 20.0 { // east win.window.drag_resize_window(ResizeDirection::West).unwrap();
window.drag_resize_window(ResizeDirection::East).unwrap(); } else if win.mouse_pos.x > width - 20.0 { // east
} else if mouse_pos.y > height - 20.0 { // south win.window.drag_resize_window(ResizeDirection::East).unwrap();
window.drag_resize_window(ResizeDirection::South).unwrap(); } else if win.mouse_pos.y > height - 20.0 { // south
} else if mouse_pos.y < 20.0 { // north win.window.drag_resize_window(ResizeDirection::South).unwrap();
window.drag_resize_window(ResizeDirection::North).unwrap(); } else if win.mouse_pos.y < 20.0 { // north
win.window.drag_resize_window(ResizeDirection::North).unwrap();
} else { // else } else { // else
window.drag_window(); win.window.drag_window();
} }
} }
}, },
WindowEvent::CursorMoved { device_id, position } => { WindowEvent::CursorMoved { device_id, position } => {
mouse_pos = position; win.mouse_pos = position;
let (width, height) = { let (width, height) = {
let size = window.inner_size(); let size = win.window.inner_size();
(size.width as f64, size.height as f64) (size.width as f64, size.height as f64)
}; };
if position.x > width - 30.0 && position.y < 30.0 { if position.x > width - 30.0 && position.y < 30.0 {
window.set_cursor_icon(CursorIcon::Pointer); win.window.set_cursor_icon(CursorIcon::Pointer);
} else if position.x < 20.0 || position.x > width - 20.0 { } else if position.x < 20.0 || position.x > width - 20.0 {
window.set_cursor_icon(CursorIcon::EwResize) win.window.set_cursor_icon(CursorIcon::EwResize)
} else if position.y < 20.0 || position.y > height - 20.0 { } else if position.y < 20.0 || position.y > height - 20.0 {
window.set_cursor_icon(CursorIcon::NsResize) win.window.set_cursor_icon(CursorIcon::NsResize)
} else { } else {
window.set_cursor_icon(CursorIcon::Pointer); win.window.set_cursor_icon(CursorIcon::Pointer);
} }
}, },
WindowEvent::RedrawRequested => { WindowEvent::RedrawRequested => {
let (width, height) = { // объявляем переменные let (width, height) = {
let size = window.inner_size(); // берем размер let size = win.window.inner_size();
(size.width, size.height) // засовываем размер в тупл и выводим в переменные (size.width, size.height)
}; };
surface win.surface
.resize( // изменение размера сурфейса .resize(
NonZeroU32::new(width).unwrap(), NonZeroU32::new(width).unwrap(),
NonZeroU32::new(height).unwrap(), NonZeroU32::new(height).unwrap(),
) )
@ -173,9 +242,20 @@ fn popup_clipboard(content: ClipboardContent) {
let mut pixmap = Pixmap::new(width, height).unwrap(); // берем let mut pixmap = Pixmap::new(width, height).unwrap(); // берем
pixmap.fill(Color::WHITE); 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);
let mut buffer = surface.buffer_mut().unwrap(); 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 { for index in 0..(width * height) as usize {
buffer[index] = pixmap.data()[index * 4 + 2] as u32 buffer[index] = pixmap.data()[index * 4 + 2] as u32
| (pixmap.data()[index * 4 + 1] as u32) << 8 | (pixmap.data()[index * 4 + 1] as u32) << 8
@ -185,17 +265,38 @@ fn popup_clipboard(content: ClipboardContent) {
buffer.present().unwrap(); buffer.present().unwrap();
}, },
_ => (), _ => (),
}
}, },
_ => (), _ => (),
} }
}).unwrap(); }).unwrap();
}
window.set_visible(false); fn popup_clipboard(content: ClipboardContent) -> WindowBuilder {
WindowBuilder::new()
.with_enabled_buttons(WindowButtons::empty())
.with_decorations(false)
.with_window_level(WindowLevel::AlwaysOnTop)
.with_title("FONotes - ".to_owned() + (match content {
ClipboardContent::Image(_) => "Image",
ClipboardContent::Text(_) => "Text",
_ => "???"
}))
.with_inner_size(LogicalSize::new(800.0, 600.0))
.with_resizable(true)
.with_visible(true)
.with_min_inner_size(LogicalSize::new(50.0, 50.0))
} }
fn main() { fn main() {
let event_loop = create_event_loop();
let windows = RefCell::new(Vec::new());
let event_loop_proxy = event_loop.create_proxy();
thread::spawn(move || {
let mut pressed: Vec<Key> = Vec::new(); let mut pressed: Vec<Key> = Vec::new();
let mut clipboard = Arc::new(Mutex::new(Clipboard::new().unwrap())); let mut clipboard = Clipboard::new().unwrap();
listen(move |event: rdev::Event| { listen(move |event: rdev::Event| {
if let EventType::KeyPress(key) = event.event_type { if let EventType::KeyPress(key) = event.event_type {
@ -206,14 +307,15 @@ fn main() {
if key == Key::KeyN && if key == Key::KeyN &&
pressed.contains(&Key::ControlLeft) && pressed.contains(&Key::ControlLeft) &&
pressed.contains(&Key::Alt) { pressed.contains(&Key::Alt) {
let mut clipboard_now = clipboard.clone(); event_loop_proxy.send_event(popup_clipboard(get_clipboard(&mut clipboard))).unwrap();
thread::spawn(move || { popup_clipboard(get_clipboard(&mut clipboard_now.lock().unwrap())) });
} }
} else if let EventType::KeyRelease(key) = event.event_type { } else if let EventType::KeyRelease(key) = event.event_type {
if pressed.contains(&key) { if pressed.contains(&key) {
pressed.remove(pressed.iter().position(|x| *x == key).unwrap()); pressed.remove(pressed.iter().position(|x| *x == key).unwrap());
} }
} }
});
});
}).unwrap(); run_event_loop(event_loop, windows);
} }