diff --git a/.gitignore b/.gitignore index a3ed5e9..e844225 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ Thumbs.db # Claude specific **/.claude/settings.local.json +private-dev/ diff --git a/docs/features/screenshot-export.md b/docs/features/screenshot-export.md new file mode 100644 index 0000000..1b1eb88 --- /dev/null +++ b/docs/features/screenshot-export.md @@ -0,0 +1,58 @@ +# Screenshot Export Feature + +## Overview +The Screenshot Export feature allows users to capture screenshots of the BERT system diagrams and save them to disk. This feature is essential for documentation, presentations, and sharing visual system models with others. + +## Implementation +The feature uses a two-part architecture: +1. **Tauri Backend**: Handles file save dialogs and file operations +2. **Leptos Frontend**: Provides UI controls and event coordination + +**Note:** This initial implementation provides the UI and dialog workflow but contains a placeholder for the actual screenshot capture functionality, which will be fully implemented in a future update. + +### Key Components + +#### Backend (Tauri) +- **Dependencies**: `chrono` for timestamp generation +- **Commands**: + - `take_screenshot`: Captures a screenshot without saving + - `save_screenshot_with_dialog`: Captures and opens a save dialog + +#### Frontend (Leptos) +- **UI Component**: `ScreenshotControls` - Floating controls in the bottom-right corner +- **Events**: `ScreenshotEvent` for Bevy-Leptos communication +- **Hooks**: `use_screenshot` for programmatic screenshot capture + +### User Interface +The UI provides two buttons: +- **Save Screenshot**: Captures and shows a save dialog +- **Quick Screenshot**: Captures without saving (for quick preview) + +A status message appears below the buttons to show the result of the screenshot operation. + +## User Experience +1. Click "Save Screenshot" or "Quick Screenshot" button +2. For "Save Screenshot": + - A save dialog appears with a default filename including timestamp + - User selects location and confirms + - Status message confirms successful save with path +3. For "Quick Screenshot": + - Status message confirms capture (screenshot is not saved to disk) + +## Technical Details + +### Event Flow +1. User clicks screenshot button in Leptos UI +2. Tauri command is invoked via WASM bindings +3. Screenshot is captured by `tauri-plugin-screenshots` +4. Result is returned to Leptos UI +5. Status message is updated accordingly + +### File Format +Screenshots are saved as PNG images with the naming format: `bert_screenshot_YYYYMMDD_HHMMSS.png` + +## Future Enhancements +- Add keyboard shortcuts (e.g., Ctrl+S for Save Screenshot) +- Implement image format options (PNG, JPG, SVG) +- Add annotation capabilities +- Provide option to copy to clipboard \ No newline at end of file diff --git a/src/bevy_app/systems/screenshot.rs b/src/bevy_app/systems/screenshot.rs new file mode 100644 index 0000000..f549abc --- /dev/null +++ b/src/bevy_app/systems/screenshot.rs @@ -0,0 +1,61 @@ +//! This module contains the systems for taking and saving screenshots. +use bevy::{ + prelude::*, + render::view::screenshot::{Screenshot, ScreenshotFinished}, + window::PrimaryWindow, +}; +use std::path::PathBuf; + +/// A resource to hold the path for the next screenshot. +#[derive(Resource, Deref, DerefMut)] +pub struct ScreenshotFile(PathBuf); + +/// Takes a screenshot when the user presses the appropriate key combination. +/// +/// This system follows the pattern of other direct keyboard shortcuts in the application. +pub fn take_screenshot( + input: Res>, + main_window: Query>, + mut commands: Commands, +) { + // Using Command on macs, Control on windows/linux. + let modifier = if cfg!(target_os = "macos") { + KeyCode::SuperLeft + } else { + KeyCode::ControlLeft + }; + + if input.pressed(modifier) && input.just_pressed(KeyCode::KeyP) { + let timestamp = chrono::Local::now().format("%Y-%m-%d_%H-%M-%S"); + let path = PathBuf::from(format!("bert_screenshot_{}.png", timestamp)); + commands.insert_resource(ScreenshotFile(path)); + let screenshot_entity = commands.spawn(Screenshot::window(main_window.single())).id(); + info!("Taking screenshot, saving to entity {:?}", screenshot_entity); + } +} + +/// Saves the screenshot to the path specified in the `ScreenshotFile` resource +/// once the `ScreenshotFinished` event is received. +pub fn save_screenshot_to_disk( + mut screenshot_events: EventReader, + mut commands: Commands, + screenshot_file: Option>, +) { + if let Some(screenshot_file) = screenshot_file { + for event in screenshot_events.read() { + if let Some(image_data) = &event.image_data { + let path = &screenshot_file.0; + match std::fs::write(path, image_data) { + Ok(_) => { + info!("Screenshot saved to {}", path.display()); + } + Err(e) => { + error!("Failed to save screenshot: {}", e); + } + } + // Remove the resource so we don't try to save again. + commands.remove_resource::(); + } + } + } +} \ No newline at end of file