use crate::utils::{self, Coord, ImageContainer, ImageProperties}; use fltk::{ app, button::Button, draw, enums::Event, frame::Frame, group::Flex, prelude::*, window::Window, }; use image::GenericImageView; use std::{ cell::RefCell, rc::Rc, sync::{Arc, RwLock}, }; static mut PATH: String = String::new(); /// Window to crop the existing image pub(crate) struct CropWindow { pub win: Window, apply_btn: Button, container: Rc>>, page: Page, } #[derive(Clone)] pub(crate) struct Page { pub(crate) image_view: Frame, pub(crate) row_flex: Flex, pub(crate) col_flex: Flex, } impl CropWindow { pub(crate) fn new() -> Self { let mut win = Window::new(0, 0, 500, 600, "Crop").center_screen(); let mut main_flex = Flex::default().size_of_parent().column(); // Work area let center_row_flex = Flex::default().row(); Frame::default(); let center_col_flex = Flex::default().column(); Frame::default(); let img_view = Frame::default(); Frame::default(); center_col_flex.end(); Frame::default(); center_row_flex.end(); // Panel let top_padding_btn = Frame::default(); let mut panel_flex = Flex::default().row(); Frame::default(); let apply_btn = Button::default().with_label("apply"); Frame::default(); panel_flex.set_size(&apply_btn, 100); panel_flex.end(); let bottom_padding_btn = Frame::default(); main_flex.set_size(&top_padding_btn, 5); main_flex.set_size(&panel_flex, 30); main_flex.set_size(&bottom_padding_btn, 5); main_flex.end(); win.end(); win.make_modal(true); win.make_resizable(true); let mut crop_win = Self { win, apply_btn, container: Rc::new(RefCell::new(None)), page: Page { image_view: img_view, row_flex: center_row_flex, col_flex: center_col_flex, }, }; crop_win.draw(); crop_win.event(); crop_win } /// Call it to show window to crop image pub(crate) fn load_to_crop( &mut self, path: &str, crop_pos: Option<(f64, f64)>, ) -> Option<(f64, f64)> { unsafe { PATH = path.to_owned(); } let mut container = ImageContainer::new(path, Arc::new(RwLock::new(ImageProperties::new()))); { let prop = &mut container.properties.write().unwrap(); prop.dimension = prop.original_dimension; prop.crop_position = match crop_pos { Some(a) => Some(a), None => Some((0.0, 0.0)), }; } container.apply_scale(); let (image_width, image_height): (f64, f64) = Coord::from(container.image.dimensions()).into(); self.win.set_size(image_width as i32, 600); self.page .row_flex .set_size(&self.page.col_flex, image_width as i32); self.page.row_flex.recalc(); self.page .col_flex .set_size(&self.page.image_view, image_height as i32); self.page.col_flex.recalc(); *self.container.borrow_mut() = Some(container); self.page.image_view.redraw(); self.win.show(); while self.win.shown() { app::wait(); } if let Some(cont) = &*self.container.borrow() { cont.properties.read().unwrap().crop_position } else { None } } fn draw(&mut self) { let container = Rc::clone(&self.container); self.page.image_view.draw(move |f| { if let Some(cont) = &*container.borrow() { let image = &cont.buffer; draw::draw_image( image.as_rgb8().unwrap().as_raw(), f.x(), f.y(), image.width() as i32, image.height() as i32, fltk::enums::ColorDepth::Rgb8, ) .unwrap(); let prop = cont.properties.read().unwrap(); let (original_width, original_height) = prop.original_dimension; let (original_x, original_y) = prop.crop_position.unwrap(); let (resized_width, resized_height) = (image.width() as f64, image.height() as f64); let (bound_width, bound_height) = utils::get_4_5(resized_width, resized_height); let (bound_x, bound_y) = ( (original_x * resized_width as f64) / original_width, (original_y * resized_height as f64) / original_height, ); draw::set_color_rgb(255, 0, 0); draw::draw_rect( f.x() + bound_x as i32, f.y() + bound_y as i32, bound_width as i32, bound_height as i32, ); } }); } fn event(&mut self) { let mut last: Option<(f64, f64)> = None; let container = Rc::clone(&self.container); self.page.image_view.handle(move |f, ev| { if let Some(cont) = &*container.borrow_mut() { let image = &cont.buffer; let mut prop = cont.properties.write().unwrap(); let (original_x, original_y) = prop.crop_position.unwrap(); let (original_width, original_heigth) = prop.original_dimension; let (original_bound_width, original_bound_height) = utils::get_4_5(original_width, original_heigth); let point = original_width / image.width() as f64; let (event_x, event_y) = ( (app::event_x() - f.x()) as f64 * point, (app::event_y() - f.y()) as f64 * point, ); if ev == Event::Push { last = Some((event_x, event_y)); } else if ev == Event::Drag { if let Some((lx, ly)) = last { let dx = event_x - lx; if (dx > 0.0 && original_x + original_bound_width < original_width) || (dx < 0.0 && original_x > 0.0) { let mut new_x = original_x + dx; if new_x + original_bound_width > original_width { new_x = original_width - original_bound_width; } else if new_x < 0.0 { new_x = 0.0; } prop.crop_position = prop.crop_position.map(|(_, y)| (new_x, y)); } let dy = event_y - ly; if (dy > 0.0 && original_y + original_bound_height < original_heigth) || (dy < 0.0 && original_y > 0.0) { let mut new_y = original_y + dy; if new_y + original_bound_height > original_heigth { new_y = original_heigth - original_bound_height; } else if new_y < 0.0 { new_y = 0.0; } prop.crop_position = prop.crop_position.map(|(x, _)| (x, new_y)); } f.redraw(); last = Some((event_x, event_y)); } } else if ev == Event::Released { last = None; } } true }); let mut wind = self.win.clone(); self.apply_btn.set_callback(move |_| { wind.do_callback(); }); } }