### Clipboard Daemon (Linux) Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/lib.rs.html Provides functionality to run a clipboard daemon, specifically for Linux operating systems. This includes constants for the daemon ID and the function to start the daemon. ```APIDOC ## run_clipboard_daemon() ### Description Runs the clipboard daemon for Linux systems. ### Platform `#[cfg(target_os = "linux")]` ### Constants - `CLIPBOARD_DAEMON_ID`: Identifier for the clipboard daemon. ``` -------------------------------- ### Selection Speed Implementation Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/selection.rs.html Provides a method to get the multiplier for selection resizing based on the current speed setting. ```rust impl Speed { /// For a given px of cursor movement, how many px does the selection resize by? pub const fn speed(self) -> f32 { match self { Self::Regular => 1.0, Self::Slow { .. } => 0.1, } } } ``` -------------------------------- ### Selection Size and Position Methods Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/selection.rs.html Provides methods to get the size and position of the selection's rectangle. These delegate to the underlying `rect` field. ```rust pub fn size(self) -> Size; /// Top left corner of the selection pub fn pos(self) -> Point; /// Top-left, top-right, bottom-left and bottom-right points pub fn corners(self) -> Corners; /// Whether this selection contains a given point pub fn contains(self, point: Point) -> bool; /// Position of the top left corner pub fn top_left(self) -> Point; /// Position of the top right corner pub fn top_right(self) -> Point; /// Position of the bottom right corner pub fn bottom_right(self) -> Point; /// Position of the bottom left corner pub fn bottom_left(self) -> Point; ``` -------------------------------- ### Explainer Trait Implementation Example Source: https://docs.rs/ferrishot/0.2.0/ferrishot/trait.Explainer.html Shows a generic implementation of the Explainer trait for any type `E` that can be converted into an `Element`. This allows types that implement `Into` to be used with the `explain` method. ```rust impl<'a, M: 'a, E> Explainer<'a, M> for E where E: Into>, ``` -------------------------------- ### Render Welcome Message with Key Bindings Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/app.rs.html Constructs and displays a welcome message with key bindings for user actions. It uses a helper function 'keys' to format key-action pairs. ```rust fn render_welcome_message<'a>(&self) -> Element<'a, Message> { use iced::widget::text; const WIDTH: u32 = 380; const HEIGHT: u32 = 160; const FONT_SIZE: f32 = 13.0; let (width, height, _) = self.screenshot.raw(); let vertical_space = Space::with_height(height / 2 - HEIGHT / 2); let horizontal_space = Space::with_width(width / 2 - WIDTH / 2); let bold = Font { weight: iced::font::Weight::Bold, ..Font::default() }; let keys = |key: &'static str, action: &'static str| { row![ row![ Space::with_width(Length::Fill), text(key) .size(FONT_SIZE) .font(bold) .shaping(Shaping::Advanced) .align_y(Vertical::Bottom) ] .width(100.0), Space::with_width(Length::Fixed(20.0)), text(action).size(FONT_SIZE).align_y(Vertical::Bottom), ] }; let stuff = iced::widget::container( column![ keys("Mouse", "Select screenshot area"), keys("Ctrl + S", "Save screenshot to a file"), keys("Enter", "Copy screenshot to clipboard"), keys("Right Click", "Snap closest corner to mouse"), keys("Shift + Mouse", "Slowly resize / move area"), keys("Esc", "Exit"), ] .spacing(8.0) .height(HEIGHT) .width(WIDTH) .padding(10.0), ) .style(|_| iced::widget::container::Style { text_color: Some(THEME.fg_on_accent_bg), ``` -------------------------------- ### Get Top-Left Position Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/rectangle.rs.html Returns the position of the top-left corner of the rectangle. ```APIDOC ## pos ### Description Returns the position of the top-left corner of the rectangle. ### Method `fn pos(self) -> Point` ``` ```APIDOC ## top_left ### Description Returns the position of the top-left corner of the rectangle. ### Method `fn top_left(&self) -> Point` ``` -------------------------------- ### Get Bottom-Left Position Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/rectangle.rs.html Calculates and returns the position of the bottom-left corner of the rectangle. ```APIDOC ## bottom_left ### Description Returns the position of the bottom-left corner of the rectangle. ### Method `fn bottom_left(&self) -> Point` ``` -------------------------------- ### Define and Parse App Configuration Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/config.rs.html Defines the application's configuration structure using `clap::Parser` and initializes it lazily. The `instant` flag controls clipboard behavior. ```rust 1//! Command line arguments to configure the program 2use std::sync::LazyLock; 3 4use clap::Parser; 5 6/// Configuration of the app 7pub static CONFIG: LazyLock = LazyLock::new(Config::parse); 8 9/// Configuration for the program 10#[derive(Parser, Debug)] 11#[command(version, about, author = "Nik Revenco")] 12pub struct Config { 13 /// The first selection will be copied to the clipboard as soon as the left mouse button is released 14 #[arg(long)] 15 pub instant: bool, 16} ``` -------------------------------- ### Get Bottom-Right Position Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/rectangle.rs.html Calculates and returns the position of the bottom-right corner of the rectangle. ```APIDOC ## bottom_right ### Description Returns the position of the bottom-right corner of the rectangle. ### Method `fn bottom_right(&self) -> Point` ``` -------------------------------- ### App Module Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/lib.rs.html Exposes the main application struct and a constant for saved images. ```APIDOC ## App ### Description The main application struct for ferrishot. ### Constants - `SAVED_IMAGE`: Represents a saved image within the application. ``` -------------------------------- ### Get Top-Right Position Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/rectangle.rs.html Calculates and returns the position of the top-right corner of the rectangle. ```APIDOC ## top_right ### Description Returns the position of the top-right corner of the rectangle. ### Method `fn top_right(&self) -> Point` ``` -------------------------------- ### Application View Rendering Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/app.rs.html Renders the application's user interface using Iced widgets. It stacks a background image, a canvas for drawing, and optionally a welcome message. ```rust impl App { /// Renders the app pub fn view(&self) -> iced::Element { Stack::new() // taken screenshot in the background .push(BackgroundImage::new(self.screenshot.clone().into())) // border around the selection .push(canvas(self).width(Length::Fill).height(Length::Fill)) // information popup, when there is no selection .push_maybe( self.selection .is_none() .then(|| self.render_welcome_message()), ) } } ``` -------------------------------- ### App::view Implementation Source: https://docs.rs/ferrishot/0.2.0/ferrishot/struct.App.html Renders the application's user interface. This method is responsible for drawing all visual elements based on the current application state. ```rust pub fn view(&self) -> Element<'_, Message> ``` -------------------------------- ### Rectangle Position Accessors Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/rectangle.rs.html Provides convenient methods to get the position of the top-left corner and other corners of the rectangle. ```rust /// Position of the top left corner fn pos(self) -> Point { self.position() } ``` ```rust /// Position of the top left corner fn top_left(&self) -> Point { self.position() } ``` ```rust /// Position of the top right corner fn top_right(&self) -> Point { self.top_left().with_x(|x| x + self.width) } ``` ```rust /// Position of the bottom right corner fn bottom_right(&self) -> Point { self.top_left() .with_x(|x| x + self.width) .with_y(|y| y + self.height) } ``` ```rust /// Position of the bottom left corner fn bottom_left(&self) -> Point { self.top_left().with_y(|y| y + self.height) } ``` -------------------------------- ### screenshot Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/screenshot.rs.html Takes a screenshot of the desktop at the current mouse position and returns a handle to the image. ```APIDOC /// Take a screenshot and return a handle to the image pub fn screenshot() -> Result { let mouse_position::mouse_position::Mouse::Position { x, y } = mouse_position::mouse_position::Mouse::get_mouse_position() else { return Err(ScreenshotError::MousePosition); }; let monitor = xcap::Monitor::from_point(x, y).map_err(ScreenshotError::Monitor)?; let screenshot = monitor .capture_image() .map_err(ScreenshotError::Screenshot)?; Ok(RgbaHandle::new( screenshot.width(), screenshot.height(), screenshot.into_raw(), )) } ``` -------------------------------- ### Get Rectangle Corners Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/rectangle.rs.html Calculates and returns the coordinates of the four corners (top-left, top-right, bottom-left, bottom-right) of the rectangle after normalization. ```APIDOC ## corners ### Description Obtains the coordinates of the 4 corners of the rectangle. The rectangle is normalized before calculating the corners. ### Method `fn corners(self) -> Corners` ``` -------------------------------- ### Set Image to Clipboard Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/clipboard.rs.html Sets the image content of the clipboard. It saves the image data to a temporary file and then uses a daemon process on Linux or the `arboard` crate directly on other systems. Returns the path to the temporary image file. ```rust pub fn set_image(image_data: arboard::ImageData) -> Result> { let clipboard_buffer_path = tempfile::Builder::new() .keep(true) .tempfile() .expect("failed to create a temporary file, for storage of image data"); let mut clipboard_buffer_file = File::create(&clipboard_buffer_path)?; clipboard_buffer_file.write_all(&image_data.bytes)?; #[cfg(target_os = "linux")] { use std::process; process::Command::new(std::env::current_exe()?) .arg(CLIPBOARD_DAEMON_ID) .arg("image") .arg(image_data.width.to_string()) .arg(image_data.height.to_string()) .arg(clipboard_buffer_path.path()) .stdin(process::Stdio::null()) .stdout(process::Stdio::null()) .stderr(process::Stdio::null()) .current_dir("/") .spawn()?; } #[cfg(not(target_os = "linux"))] { arboard::Clipboard::new()?.set_image(image_data)?; } Ok(clipboard_buffer_path.path().to_path_buf()) } ``` -------------------------------- ### SelectionIsSome Struct Definition Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/selection.rs.html A marker type that guarantees an `Option` is `Some`. It should only be obtained via the `get` method to ensure type safety. ```rust pub struct SelectionIsSome { /// Private field makes this type impossible to construct outside of the module it is defined in _private: (), } ``` -------------------------------- ### App::create_selection_at Implementation Source: https://docs.rs/ferrishot/0.2.0/ferrishot/struct.App.html Initializes a new, empty selection at the specified point. This is typically used when the user begins a new selection action. ```rust pub fn create_selection_at(&mut self, create_selection_at: Point) ``` -------------------------------- ### Default Application State Initialization Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/app.rs.html Implements the Default trait for the App struct, providing a default initial state. This includes taking a screenshot of the desktop. ```rust impl Default for App { fn default() -> Self { let screenshot = crate::screenshot::screenshot().expect("Failed to take a screenshot of the desktop"); Self { screenshot, selection: None, selections_created: 0, errors: vec![], } } } ``` -------------------------------- ### Check and Get Mutable Reference to Selection Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/app.rs.html Checks if a cursor intersects with a selection and returns a mutable reference to the selection if it does. This allows for in-place modification of the selection. ```rust fn cursor_in_selection_mut(&mut self, cursor: Cursor) -> Option<(Point, &mut Selection)> { self.selection.as_mut().and_then(|sel| { cursor .position() .and_then(|cursor_pos| sel.norm().contains(cursor_pos).then_some((cursor_pos, sel))) }) } ``` -------------------------------- ### OptionalSelectionExt Trait Implementation Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/selection.rs.html Provides an extension trait for `Option` to safely unwrap it. The `get` method returns the selection and a `SelectionIsSome` token, ensuring the selection exists. ```rust #[easy_ext::ext(OptionalSelectionExt)] pub impl Option { /// Attempt to get the inner selection. if successful, return a key that allows opening /// this option again with a guarantee for existance. fn get(self) -> Option<(Selection, SelectionIsSome)> { self.map(|x| (x, SelectionIsSome { _private: () })) } } ``` -------------------------------- ### Copy Text to Clipboard Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/clipboard.rs.html Use this function to copy plain text to the system clipboard. Ensure the 'arboard' crate is initialized and available. ```rust let text = args.next().expect("text"); assert_eq!(args.next(), None, "unexpected extra args"); arboard::Clipboard::new()?.set().wait().text(text)?; ``` -------------------------------- ### Create a Tooltip Widget Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/widgets.rs.html Creates a tooltip element with custom styling for its background and text color. It allows specifying the content, tooltip message, and its position relative to the content. ```rust /// Create a tooltip for an icon pub fn icon_tooltip<'a, Message>( content: impl Into>, tooltip: impl Into>, position: widget::tooltip::Position, ) -> widget::Tooltip<'a, Message> { widget::Tooltip::new(content, tooltip, position) .style(|_| widget::container::Style { text_color: Some(THEME.fg), background: Some(Background::Color(THEME.bg)), border: Border::default(), shadow: Shadow::default(), }) .gap(10.0) } ``` -------------------------------- ### create_selection_at Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/app.rs.html Creates a new, empty selection at the specified point. This selection is initially in a 'Create' status. ```APIDOC ## create_selection_at ### Description Creates a new, empty selection at the specified point. This selection is initially in a 'Create' status. ### Method `pub fn create_selection_at(&mut self, create_selection_at: Point)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust // Assuming `app` is a mutable instance of the application and `point` is a Point object app.create_selection_at(point); ``` ### Response #### Success Response This method does not return a value, but modifies the application's state by creating a new selection. #### Response Example ```json { "example": "No explicit return value, state is modified." } ``` ``` -------------------------------- ### Create New Selection Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/app.rs.html Initializes a new selection at a specified point. The selection's status is set to 'Create', and a counter for created selections is incremented. ```rust pub fn create_selection_at(&mut self, create_selection_at: Point) { let mut selection = Selection::new(create_selection_at); selection.status = SelectionStatus::Create; self.selections_created += 1; self.selection = Some(selection); } ``` -------------------------------- ### Get Mouse Interaction for Side or Corner Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/corners.rs.html Determines the appropriate mouse cursor interaction based on whether the cursor is over a side or a corner of a rectangle. Used for visual feedback during resizing operations. ```rust impl SideOrCorner { /// Obtain the appropriate mouse cursor for the given side pub const fn mouse_icon(self) -> mouse::Interaction { match self { Self::Side(side) => match side { Side::Top | Side::Bottom => mouse::Interaction::ResizingVertically, Side::Right | Side::Left => mouse::Interaction::ResizingHorizontally, }, Self::Corner(corner) => match corner { Corner::TopLeft | Corner::BottomRight => mouse::Interaction::ResizingDiagonallyDown, Corner::TopRight | Corner::BottomLeft => mouse::Interaction::ResizingDiagonallyUp, }, } } } ``` -------------------------------- ### Run Clipboard Daemon (Linux) Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/clipboard.rs.html Runs a background process that provides clipboard access on Linux systems. This daemon is intended to be invoked by the main application and handles clipboard operations until the user copies something new. ```APIDOC ## run_clipboard_daemon ### Description Runs a process in the background that provides clipboard access, until the user copies something else into their clipboard. This function is only available on Linux. ### Function Signature `#[cfg(target_os = "linux")] pub fn run_clipboard_daemon() -> Result<(), arboard::Error>` ### Errors - Could not create a clipboard. - Could not set the clipboard text or image. ### Panics Will panic if the daemon was invoked incorrectly (e.g., wrong number of arguments, invalid image dimensions). This is expected as it's an internal mechanism. ### Expected Arguments (for daemon process) 1. `__ferrishot_clipboard_daemon` (ID) 2. Copy type: `"text"` or `"image"` If copy type is `"image"`, expected arguments are: 3. Width of image (usize) 4. Height of image (usize) 5. Path to image bytes If copy type is `"text"`, expected argument is: 3. Text content to copy. ``` -------------------------------- ### Run Linux Clipboard Daemon Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/clipboard.rs.html Runs a background process on Linux to provide clipboard access. This function is intended to be invoked by the main application and expects specific arguments to determine whether to handle text or image data. It panics if invoked incorrectly. ```rust pub fn run_clipboard_daemon() -> Result<(), arboard::Error> { use arboard::SetExtLinux as _; use std::fs; log::info!( "Spawned clipboard daemon with arguments: {:?}", std::env::args().collect::>() ); // skip program name let mut args = std::env::args().skip(1); assert_eq!( args.next().as_deref(), Some(CLIPBOARD_DAEMON_ID), "this function must be invoked from a daemon process" ); match args.next().expect("has copy type").as_str() { "image" => { let width = args .next() .expect("width") .parse::() .expect("valid image width"); let height = args .next() .expect("height") .parse::() .expect("valid image height"); let path = args.next().expect("image path"); let bytes: std::borrow::Cow<[u8]> = fs::read(&path).expect("image contents").into(); assert_eq!(args.next(), None, "unexpected extra args"); assert_eq!( width * height * 4, bytes.len(), "every 4 bytes in `bytes` represents a single RGBA pixel" ); arboard::Clipboard::new()?. set() } _ => unimplemented!(), } Ok(()) } ``` -------------------------------- ### Layouting Selection with Icons (Rust) Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/selection.rs.html Constructs the final layout for the selection component, including vertical spacing for top icons, the main selection area with left/right icons, and bottom icons. It calculates necessary padding and heights to align elements correctly. ```rust let selection_height = FRAME_WIDTH.mul_add(2.0, sel.rect.height); let height_added = (PX_PER_ICON - selection_height).max(0.0); iced::widget::column![ Space::with_height(Length::Fixed( (top_icon_rows_count as f32).mul_add(-PX_PER_ICON, sel.rect.y - height_added / 2.0) )) .width(Length::Fill), top_icons, row![Space::with_width(sel.rect.x - PX_PER_ICON).height(Length::Fill),] .push_maybe(left_icons) .push( Space::with_width(FRAME_WIDTH.mul_add(2.0, sel.rect.width)) .height(Length::Fill) ) .push_maybe(right_icons) .padding(Padding::default().top(height_added / 2.0)) .height(selection_height + height_added), ``` -------------------------------- ### Selection::new Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/selection.rs.html Creates a new Selection at a given point with a default size of zero. ```APIDOC ## Selection::new ### Description Creates a new Selection at a given point with a default size of zero. ### Signature ```rust pub fn new(point: Point) -> Self ``` ### Parameters * `point` (Point) - The starting point for the new selection. ### Returns `Self` - A new Selection instance. ``` -------------------------------- ### Config Module Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/lib.rs.html Exposes configuration-related elements. ```APIDOC ## CONFIG ### Description Configuration settings for the ferrishot application. ``` -------------------------------- ### Implement canvas::Program for App Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/canvas.rs.html Implements the canvas drawing and interaction logic for the application. Requires a MouseState struct to track mouse button and modifier key states. ```rust impl canvas::Program for App { type State = MouseState; fn draw( &self, _state: &Self::State, renderer: &Renderer, _theme: &Theme, bounds: Rectangle, _cursor: mouse::Cursor, ) -> Vec { let mut frame = canvas::Frame::new(renderer, bounds.size()); self.render_shade(&mut frame, bounds); if let Some(selection) = self.selection.map(Selection::norm) { selection.render_border(&mut frame, THEME.accent); selection.corners().render_circles(&mut frame, THEME.accent); } vec![frame.into_geometry()] } fn mouse_interaction( &self, _state: &Self::State, _bounds: Rectangle, cursor: iced::advanced::mouse::Cursor, ) -> iced::advanced::mouse::Interaction { self.selection // mouse button for resizing the selection .and_then(|sel| { // if we are already resizing, then this cursor takes priority // e.g. we are resizing horizontally but we are on the top left // corner = we should have horizontal resize cursor. (if let SelectionStatus::Resize { resize_side, .. } = sel.status { Some(resize_side.mouse_icon()) } else if sel.status.is_move() { Some(Interaction::Grabbing) } else { None }) .or_else(|| { // when we started dragging a side, even if we go outside of the bounds of that side (which // happens often when we are dragging the mouse fast), we don't want the cursor to change cursor.position().and_then(|cursor| { sel.corners().side_at(cursor).map(SideOrCorner::mouse_icon) }) }) }) .unwrap_or_else(|| { if self.cursor_in_selection(cursor).is_some() { Interaction::Grab } else { Interaction::Crosshair } }) } fn update( &self, state: &mut Self::State, event: &iced::Event, _bounds: Rectangle, cursor: iced::advanced::mouse::Cursor, ) -> Option> { let message = match event { Mouse(ButtonPressed(Left)) => { state.is_left_down = true; Message::LeftMouseDown(cursor) } Mouse(ButtonPressed(Right)) => { state.is_right_down = true; if let Some(cursor) = cursor.position() { if let Some((selection, sel_is_some)) = self.selection.get() { Message::ResizeToCursor { cursor_pos: cursor, selection: selection.norm(), sel_is_some, } } else { return None; } } else { return None; } } Mouse(ButtonReleased(Right)) => { state.is_right_down = false; Message::EnterIdle } Mouse(ButtonReleased(Left)) => { state.is_left_down = false; ``` -------------------------------- ### Set Text to Clipboard Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/clipboard.rs.html Sets the text content of the clipboard. On Linux, it spawns a daemon process to handle this. On other operating systems, it uses the `arboard` crate directly. ```rust pub fn set_text(text: &str) -> Result<(), Box> { #[cfg(target_os = "linux")] { use std::process; process::Command::new(std::env::current_exe()?) .arg(CLIPBOARD_DAEMON_ID) .arg("text") .arg(text) .stdin(process::Stdio::null()) .stdout(process::Stdio::null()) .stderr(process::Stdio::null()) .current_dir("/") .spawn()?; } #[cfg(not(target_os = "linux"))] { arboard::Clipboard::new()?.set_text(text)?; } Ok(()) } ``` -------------------------------- ### Create a Size Indicator Widget Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/widgets.rs.html Renders a numeric input for displaying and resizing a rectangle's dimensions. It includes helper functions for creating dimension inputs and arranging them within a container. ```rust /// Renders a tiny numeric input which shows a dimension of the rect and allow resizing it pub fn size_indicator<'a>( image_height: u32, image_width: u32, rect: Rectangle, sel_is_some: SelectionIsSome, ) -> Element<'a, Message> { fn dimension_indicator<'a>(value: u32, on_change: impl Fn(u32) -> Message + 'a) -> widget::TextInput<'a, Message> { let content = value.to_string(); let input = iced::widget::text_input(Default::default(), content.as_str()) // HACK: iced does not provide a way to mimic `width: min-content` from CSS // so we have to "guesstimate" the width that each character will be // `Length::Shrink` makes `width = 0` for some reason .width(Length::Fixed((12 * content.len()) as f32)) .on_input(move |s| { // if we get "" it means user e.g. just deleted everything if s.is_empty() { on_change(0) } else { s.parse::().ok().map_or(Message::NoOp, &on_change) } }) .style(|_, _| widget::text_input::Style { value: THEME.size_indicator_fg, selection: THEME.text_selection_bg, // --- none background: Background::Color(THEME.transparent), border: iced::Border { color: THEME.transparent, width: 0.0, radius: 0.0.into(), }, icon: THEME.transparent, placeholder: THEME.transparent, }) .padding(0.0); input } const SPACING: f32 = 12.0; const ESTIMATED_INDICATOR_WIDTH: u32 = 120; const ESTIMATED_INDICATOR_HEIGHT: u32 = 26; let x_offset = (rect.bottom_right().x + SPACING).min((image_width - ESTIMATED_INDICATOR_WIDTH) as f32); let y_offset = (rect.bottom_right().y + SPACING).min((image_height - ESTIMATED_INDICATOR_HEIGHT) as f32); let horizontal_space = Space::with_width(x_offset); let vertical_space = Space::with_height(y_offset); let width = dimension_indicator(rect.width as u32, move |new_width| { Message::ResizeHorizontally { new_width, sel_is_some, } }); let height = dimension_indicator(rect.height as u32, move |new_height| { Message::ResizeVertically { new_height, sel_is_some, } }); let x = iced::widget::text("✕ ") .color(THEME.fg) .shaping(Shaping::Advanced); let space = iced::widget::text(" "); let c = widget::container(row![space, width, x, height]).style(|_| widget::container::Style { text_color: None, background: Some(Background::Color(THEME.size_indicator_bg)), border: iced::Border::default(), shadow: iced::Shadow::default(), }); column![vertical_space, row![horizontal_space, c]].into() } ``` -------------------------------- ### Set Text to Clipboard Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/clipboard.rs.html Sets the text content of the system clipboard. On Linux, this spawns a daemon process to handle the clipboard operation. On other operating systems, it uses the `arboard` crate directly. ```APIDOC ## set_text ### Description Sets the text content of the clipboard. ### Function Signature `pub fn set_text(text: &str) -> Result<(), Box>` ### Parameters - **text** (`&str`) - The text content to set to the clipboard. ### Returns - `Ok(())` on success. - `Err(Box)` if any error occurs during the operation. ``` -------------------------------- ### Capture Desktop Screenshot Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/screenshot.rs.html Captures a screenshot of the desktop at the current mouse cursor's position. Requires the `mouse-position` and `xcap` crates. Returns a `RgbaHandle` on success or a `ScreenshotError` on failure. ```rust pub fn screenshot() -> Result { let mouse_position::mouse_position::Mouse::Position { x, y } = mouse_position::mouse_position::Mouse::get_mouse_position() else { return Err(ScreenshotError::MousePosition); }; let monitor = xcap::Monitor::from_point(x, y).map_err(ScreenshotError::Monitor)?; let screenshot = monitor .capture_image() .map_err(ScreenshotError::Screenshot)?; Ok(RgbaHandle::new( screenshot.width(), screenshot.height(), screenshot.into_raw(), )) } ``` -------------------------------- ### Convert RgbaHandle to Iced Handle Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/screenshot.rs.html Allows seamless conversion of the custom `RgbaHandle` to the standard `iced::widget::image::Handle`. ```rust impl From for Handle { fn from(value: RgbaHandle) -> Self { value.0 } } ``` -------------------------------- ### Handle Select Full Screen Message Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/app.rs.html Sets the selection to cover the entire screen dimensions when the 'SelectFullScreen' message is received. ```rust Message::SelectFullScreen => { let (width, height, _) = self.screenshot.raw(); { self.selection = Some(Selection::new(Point { x: 0.0, y: 0.0 }).with_size( |_| Size { width: width as f32, height: height as f32, }, )); } } ``` -------------------------------- ### run_clipboard_daemon Source: https://docs.rs/ferrishot/0.2.0/ferrishot/fn.run_clipboard_daemon.html Runs a background process that provides clipboard access. This process terminates when the user copies new content to the clipboard. It is intended to be invoked internally by the application and not directly by external users. ```APIDOC ## Function run_clipboard_daemon ### Summary ``` pub fn run_clipboard_daemon() -> Result<(), Error> ``` ### Description Runs a process in the background that provides clipboard access, until the user copies something else into their clipboard. ### Errors - Could not create a clipboard - Could not set the clipboard text ### Panics Will panic if the daemon was invoked incorrectly. That’s fine because it should only be invoked from this app, never from the outside. We expect that the daemon receives 4 arguments: 1. ID of the daemon 2. copy type: “image” or “text” if copy type is “image” we expect: 3. width of image 4. height of image 5. path to bytes of the image The image must be of valid width, height and byte amount if copy type is “text” we expect: 3. text content which should be copied to the clipboard ``` -------------------------------- ### impl Default for App Source: https://docs.rs/ferrishot/0.2.0/ferrishot/struct.App.html Provides a default value for the App struct. This is useful for initializing the application state. ```rust fn default() -> Self ``` -------------------------------- ### App Struct Definition Source: https://docs.rs/ferrishot/0.2.0/ferrishot/struct.App.html Defines the main application state, including selection counts, screenshot data, current selection area, and any errors encountered. ```rust pub struct App { pub selections_created: usize, pub screenshot: RgbaHandle, pub selection: Option, pub errors: Vec, } ``` -------------------------------- ### impl IntoBoot for State Source: https://docs.rs/ferrishot/0.2.0/ferrishot/struct.App.html Converts a state type into the initial state and task for an Application. This is used to bootstrap the application's lifecycle. ```rust fn into_boot(self) -> (State, Task) ``` -------------------------------- ### Run Clipboard Daemon Function Signature Source: https://docs.rs/ferrishot/0.2.0/ferrishot/fn.run_clipboard_daemon.html This is the function signature for `run_clipboard_daemon`. It returns a Result indicating success or an Error type. ```rust pub fn run_clipboard_daemon() -> Result<(), Error> ``` -------------------------------- ### Define Ferrishot Theme Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/theme.rs.html Instantiates the `Theme` struct using the `theme!` macro, defining various colors used throughout the application. ```rust /// Default accent color. const ACCENT_COLOR: iced::Color = color!(0x_ab_61_37); theme! { /// Transparent: No color transparent = color!(0x_00_00_00, 0.0), /// First shadow to draw (stronger, but smaller) drop_shadow = color!(0x00_00_00, 0.5), /// Color of the background outside of the selection non_selected_region = color!(0x00_00_00, 0.5), /// Color of the background bg = color!(0x_00_00_00), /// Background color for errors error_bg = color!(0x_ff_00_00, 0.6), /// Color of text fg = color!(0x_ff_ff_ff), /// Color of text for the "width" and "height" size indicators size_indicator_fg = color!(0x_ff_ff_ff), /// Color of background text for the "width" and "height" size indicators size_indicator_bg = color!(0x_00_00_00, 0.5), /// Accent color, used for stuff like color of the frame + background /// of buttons accent = ACCENT_COLOR, /// Black or white text, depending on which one is more /// readable on a background that is `accent_bg` fg_on_accent_bg = foreground_for(ACCENT_COLOR), } ``` -------------------------------- ### Define icon Macro Source: https://docs.rs/ferrishot/0.2.0/ferrishot/macro.icon.html This macro defines the basic structure for creating an icon. It takes an identifier as input. ```rust macro_rules! icon { ($icon:ident) => { ... }; } ``` -------------------------------- ### Assembling Top Icon Rows (Rust) Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/selection.rs.html Assembles rows of icons for the top section, chaining different icon sets and filtering out empty ones. It also tracks the count of icon rows created. ```rust let mut top_icon_rows_count = 0; let top_icons: Column<_> = extra_extra_top_icons .into_iter() .chain(extra_top_icons) .chain(top_icons) .filter_map(|(icons, padding)| { (!icons.is_empty()).then(|| { top_icon_rows_count += 1; row![ Space::with_width(sel.rect.x), Row::from_vec(icons) .spacing(SPACE_BETWEEN_ICONS) .height(PX_PER_ICON) .padding(Padding::default().left(padding)) ] .into() }) }) .collect(); ``` -------------------------------- ### BackgroundImage Widget API Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/background_image.rs.html Provides details on the BackgroundImage widget's constructor and its implementation of the Widget trait for Iced. ```APIDOC ## BackgroundImage ### Description A widget that draws an image on the entire screen. ### Constructor `pub const fn new(image_handle: widget::image::Handle) -> Self` Creates a new `BackgroundImage` with the provided image handle. ### Widget Implementation Implements the `iced::advanced::Widget` trait for `BackgroundImage`. #### `size` Method Returns the size of the widget, which is set to fill the available space. - **Returns**: `Size` with `width` and `height` set to `Length::Fill`. #### `layout` Method Calculates the layout for the `BackgroundImage` widget. - **Parameters**: - `_tree`: Mutable reference to the widget tree. - `renderer`: Reference to the renderer. - `limits`: Layout limits. - **Returns**: `layout::Node` representing the widget's layout. #### `draw` Method Draws the `BackgroundImage` widget. - **Parameters**: - `_state`: Widget state. - `renderer`: Mutable reference to the renderer. - `_theme`: The current theme. - `_style`: Renderer style. - `layout`: The widget's layout information. - `_cursor`: Mouse cursor information. - `viewport`: The drawing viewport. ### `From` Implementation Allows `BackgroundImage` to be converted into an `Element`. - **Implementation**: `impl From for Element<'_, Message, Theme, Renderer>` - **Constraint**: `Renderer: iced::advanced::Renderer + iced::advanced::image::Renderer` ``` -------------------------------- ### TryFrom Source: https://docs.rs/ferrishot/0.2.0/ferrishot/struct.App.html Defines a fallible conversion from one type to another. ```APIDOC ### impl TryFrom for T where U: Into, #### type Error = Infallible ### Description The type returned in the event of a conversion error. #### fn try_from(value: U) -> Result>::Error> ### Description Performs the conversion. ``` -------------------------------- ### impl Debug for App Source: https://docs.rs/ferrishot/0.2.0/ferrishot/struct.App.html Provides a way to format the App struct for debugging purposes. This allows the struct's contents to be printed in a human-readable format. ```rust fn fmt(&self, f: &mut Formatter<'_>) -> Result ``` -------------------------------- ### Implement From for Color Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/theme.rs.html Provides a convenient way to convert an `iced::Color` into the custom `Color` wrapper. ```rust impl From for Color { fn from(value: iced::Color) -> Self { Self(value) } } ``` -------------------------------- ### Creating Left and Right Icon Columns (Rust) Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/selection.rs.html Creates Column widgets for left and right icons, applying spacing, width, and padding. These are used to display icons alongside the main selection area. ```rust let right_icons = right_icons.map(|(right_icons, right_padding)| { Column::from_vec(right_icons) .spacing(SPACE_BETWEEN_ICONS) .width(PX_PER_ICON) .padding(Padding::default().top(right_padding)) }); let left_icons = left_icons.map(|(left_icons, left_padding)| { Column::from_vec(left_icons) .spacing(SPACE_BETWEEN_ICONS) .width(PX_PER_ICON) .padding(Padding::default().top(left_padding)) }); ``` -------------------------------- ### Add Extra Icons Until Minimum Count (Top) Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/selection.rs.html Ensures a minimum number of extra icons are positioned at the top, adding more if necessary. This is called after the initial top icon placement. ```rust let extra_top_icons = extra_top_icons.map(|(extra_top_icons, extra_top_padding)| { add_icons_until_there_is_at_least_n_of_them::( extra_top_icons, &mut icons_iter, extra_top_padding, &mut total_icons_positioned, tooltip::Position::Top, ) }); ``` -------------------------------- ### TryInto Source: https://docs.rs/ferrishot/0.2.0/ferrishot/struct.App.html Defines a fallible conversion into another type. ```APIDOC ### impl TryInto for T where U: TryFrom, #### type Error = >::Error ### Description The type returned in the event of a conversion error. #### fn try_into(self) -> Result>::Error> ### Description Performs the conversion. ``` -------------------------------- ### Selection::size Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/selection.rs.html Returns the height and width of the selection. ```APIDOC ## Selection::size ### Description Returns the height and width of the selection. ### Signature ```rust pub fn size(self) -> Size ``` ### Returns `Size` - The size of the selection. ``` -------------------------------- ### Add Extra Icons Until Minimum Count (Bottom) Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/selection.rs.html Ensures a minimum number of extra icons are positioned at the bottom, adding more if necessary. This is called after the initial bottom icon placement. ```rust let extra_bottom_icons = extra_bottom_icons.map(|(extra_bottom_icons, extra_bottom_padding)| { add_icons_until_there_is_at_least_n_of_them::( extra_bottom_icons, &mut icons_iter, extra_bottom_padding, &mut total_icons_positioned, tooltip::Position::Bottom, ) }); ``` -------------------------------- ### Set Image to Clipboard Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/clipboard.rs.html Sets the image content of the system clipboard. This function saves the image data to a temporary file and then uses a daemon process on Linux or the `arboard` crate directly on other systems. ```APIDOC ## set_image ### Description Sets the image content of the clipboard. ### Function Signature `pub fn set_image(image_data: arboard::ImageData) -> Result>` ### Parameters - **image_data** (`arboard::ImageData`) - The image data to set to the clipboard. This struct contains `bytes`, `width`, and `height`. ### Returns - `Ok(std::path::PathBuf)` containing the path to the temporary file where the image was saved on success. - `Err(Box)` if any error occurs during the operation. ``` -------------------------------- ### Process Image with Selection Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/selection.rs.html Processes an image by cropping it according to the selection's rectangle. Requires image dimensions and pixel data. The `expect` calls handle potential errors during image creation and cropping. ```rust pub fn process_image(&self, width: u32, height: u32, pixels: &[u8]) -> image::DynamicImage { #[expect(clippy::cast_possible_truncation, reason = "pixels must be integer")] #[expect( clippy::cast_sign_loss, reason = "selection has been normalized so height and width will be positive" )] image::DynamicImage::from( image::RgbaImage::from_raw(width, height, pixels.to_vec()) .expect("Image handle stores a valid image"), ) .crop_imm( self.rect.x as u32, self.rect.y as u32, self.rect.width as u32, self.rect.height as u32, ) } ``` -------------------------------- ### Close Application Window Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/app.rs.html Provides a safe way to close the application window, avoiding potential segfaults that can occur with `iced::exit` in specific scenarios. ```rust fn exit() -> Task { iced::window::get_latest().then(|id| iced::window::close(id.expect("window to exist"))) } ``` -------------------------------- ### Copy Selection to Clipboard Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/app.rs.html Copies the current selection to the system clipboard. It handles cases where there is no selection and processes the image data before setting it to the clipboard. ```rust let Some(selection) = self.selection.map(Selection::norm) else { self.error("There is no selection to copy"); return Task::none(); }; let (width, height, pixels) = self.screenshot.raw(); let cropped_image = selection.process_image(width, height, pixels); let image_data = arboard::ImageData { width: cropped_image.width() as usize, height: cropped_image.height() as usize, bytes: std::borrow::Cow::Borrowed(cropped_image.as_bytes()), }; #[cfg_attr( target_os = "macos", expect(unused_variables, reason = "it is used on other platforms") )] match crate::clipboard::set_image(image_data) { Ok(img_path) => { // send desktop notification if possible, this is // just a decoration though so it's ok if we fail to do this let mut notify = notify_rust::Notification::new(); notify .summary(&format!("Copied image to clipboard {width}px * {height}px")); // images are not supported on macos #[cfg(not(target_os = "macos"))] notify.image_path(&img_path.to_string_lossy()); let _ = notify.show(); return Self::exit(); } Err(err) => { self.error(format!("Could not copy the image: {err}")); } } ``` -------------------------------- ### Define a styled icon button macro Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/icons.rs.html Use this macro to create a styled button with a specific icon. It takes an icon identifier and generates a widget. ```rust macro_rules! icon { ($icon:ident) => {{ $crate::widgets::icon($crate::icons::Icon::$icon) }}; } ``` -------------------------------- ### BackgroundImage Widget Definition Source: https://docs.rs/ferrishot/0.2.0/src/ferrishot/background_image.rs.html Defines the `BackgroundImage` struct and its associated methods for creating and managing the widget. It requires an image handle for the screenshot. ```rust 1//! Renders the full, unprocessed desktop screenshot on the screen 2use iced::advanced::widget::Tree; 3use iced::advanced::{Layout, Widget, layout, renderer}; 4use iced::widget::image; 5use iced::{Element, Length, Rectangle, Size, Theme, mouse, widget}; 6 7#[derive(Debug)] 8/// A widget that draws an image on the entire screen 9pub struct BackgroundImage { 10 /// Image handle of the full-desktop screenshot 11 image_handle: widget::image::Handle, 12} 13 14impl BackgroundImage { 15 /// Create a new `BackgroundImage` 16 pub const fn new(image_handle: widget::image::Handle) -> Self { 17 Self { image_handle } 18 } 19} ```