pub(crate) fn handle_mouse_input(app: &mut Application, mouse: MouseEvent) {
    let component =
        app.display.identify_clicked_component(mouse.row, mouse.column, app.key_handler.as_ref());
    match mouse.kind {
        MouseEventKind::Down(MouseButton::Left) => {
            app.data.last_click = component;
            match app.data.last_click {
                Window::Ascii => {
                    if let Some((cursor_pos, _)) = handle_editor_click(Window::Ascii, app, mouse) {
                        app.data.offset = cursor_pos;
                    }
                }
                Window::Hex => {
                    if let Some((cursor_pos, nibble)) = handle_editor_click(Window::Hex, app, mouse)
                    {
                        app.data.offset = cursor_pos;
                        app.data.nibble = nibble.expect("Clicking on Hex should return a nibble!");
                    }
                }
                Window::Label(_)
                | Window::Unhandled
                | Window::JumpToByte
                | Window::Search
                | Window::UnsavedChanges => {}
            }
        }
        MouseEventKind::Drag(MouseButton::Left) => {
            if app.data.drag_enabled {
                match app.data.last_click {
                    Window::Ascii => {
                        if let Some((cursor_pos, _)) = handle_editor_drag(Window::Ascii, app, mouse)
                        {
                            if app.data.last_drag.is_none() {
                                app.data.last_drag = Some(app.data.offset);
                            }
                            app.data.offset = cursor_pos;
                            app.labels.update_all(&app.data.contents[app.data.offset..]);
                            adjust_offset(&mut app.data, &mut app.display, &mut app.labels);
                        }
                    }
                    Window::Hex => {
                        if let Some((cursor_pos, nibble)) =
                            handle_editor_drag(Window::Hex, app, mouse)
                        {
                            if app.data.last_drag.is_none() {
                                app.data.last_drag = Some(app.data.offset);
                                app.data.drag_nibble = Some(app.data.nibble);
                            }
                            app.data.offset = cursor_pos;
                            app.data.nibble = nibble.unwrap();
                            app.labels.update_all(&app.data.contents[app.data.offset..]);
                            adjust_offset(&mut app.data, &mut app.display, &mut app.labels);
                        }
                    }
                    Window::Label(_)
                    | Window::Unhandled
                    | Window::JumpToByte
                    | Window::Search
                    | Window::UnsavedChanges => {}
                }
            }
        }
        MouseEventKind::Up(MouseButton::Left) => {
            match component {
                Window::Label(i) => {
                    if app.data.last_click == component {
                        // Put string into clipboard
                        if let Some(clipboard) = app.data.clipboard.as_mut() {
                            clipboard.set_text(app.labels[LABEL_TITLES[i]].clone()).unwrap();
                            app.labels.notification = format!("{} copied!", LABEL_TITLES[i]);
                        } else {
                            app.labels.notification = String::from("Can't find clipboard!");
                        }
                    }
                }
                Window::Hex
                | Window::Ascii
                | Window::Unhandled
                | Window::JumpToByte
                | Window::Search
                | Window::UnsavedChanges => {}
            }
        }
        MouseEventKind::ScrollUp => {
            let bytes_per_line = app.display.comp_layouts.bytes_per_line;

            // Scroll up a line in the viewport without changing cursor.
            app.data.start_address = app.data.start_address.saturating_sub(bytes_per_line);
        }
        MouseEventKind::ScrollDown => {
            let bytes_per_line = app.display.comp_layouts.bytes_per_line;
            let lines_per_screen = app.display.comp_layouts.lines_per_screen;

            let content_lines = app.data.contents.len() / bytes_per_line + 1;
            let start_row = app.data.start_address / bytes_per_line;

            // Scroll down a line in the viewport without changing cursor.
            // Until the viewport contains the last page of content.
            if start_row + lines_per_screen < content_lines {
                app.data.start_address = app.data.start_address.saturating_add(bytes_per_line);
            }
        }
        _ => {}
    }
}
Handles the mouse input, which consists of things like scrolling and focusing components
based on a left and right click.
src/input.rs