🎯 Ejemplos recomendados
Balanced sample collections from various categories for you to explore
Ejemplos de Características de Escritorio Web Rust
Ejemplos de características de escritorio Web Rust incluyendo diálogos de archivos, cuadros de mensajes e integración del sistema
💻 Cuadro de Mensajes rust
🟢 simple
⭐⭐
Mostrar diálogos de alerta, confirmación y prompt usando APIs del navegador
⏱️ 15 min
🏷️ rust, web, desktop features
Prerequisites:
Basic Rust, Understanding of Web APIs
// Web Rust Message Box Examples
// Alert, confirm, and prompt dialogs using browser Web APIs
//
// This demonstrates message box functionality that would work in WebAssembly (WASM) context
//
// For actual desktop message boxes, consider using:
// - Tauri (https://tauri.app/) for desktop apps
// - egui for custom modal dialogs
use serde::{Deserialize, Serialize};
// 1. Message Box Types
/// Types of message boxes
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum MessageBoxType {
Info,
Warning,
Error,
Question,
Success,
}
/// Message box buttons
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum MessageBoxButtons {
Ok,
OkCancel,
YesNo,
YesNoCancel,
AbortRetryIgnore,
}
/// Message box result
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum MessageBoxResult {
Ok,
Cancel,
Yes,
No,
Abort,
Retry,
Ignore,
}
// 2. Message Box Options
/// Options for message box
#[derive(Debug, Clone)]
struct MessageBoxOptions {
title: String,
message: String,
box_type: MessageBoxType,
buttons: MessageBoxButtons,
default_button: MessageBoxResult,
}
impl MessageBoxOptions {
fn new(title: &str, message: &str) -> Self {
MessageBoxOptions {
title: title.to_string(),
message: message.to_string(),
box_type: MessageBoxType::Info,
buttons: MessageBoxButtons::Ok,
default_button: MessageBoxResult::Ok,
}
}
fn with_type(mut self, box_type: MessageBoxType) -> Self {
self.box_type = box_type;
self
}
fn with_buttons(mut self, buttons: MessageBoxButtons) -> Self {
self.buttons = buttons;
self
}
fn with_default(mut self, default: MessageBoxResult) -> Self {
self.default_button = default;
self
}
}
// 3. Message Box Implementation (WASM-compatible)
/// Show alert dialog (simple info message)
fn show_alert(title: &str, message: &str) {
// In WASM, this would call: window.alert(message)
println!("[ALERT] {}: {}", title, message);
}
/// Show confirm dialog (yes/no)
fn show_confirm(title: &str, message: &str) -> bool {
// In WASM, this would call: window.confirm(message)
println!("[CONFIRM] {}: {}", title, message);
true // Simulated user response
}
/// Show prompt dialog (input field)
fn show_prompt(title: &str, message: &str, default: &str) -> Option<String> {
// In WASM, this would call: window.prompt(message, default)
println!("[PROMPT] {}: {} (default: {})", title, message, default);
Some(default.to_string()) // Simulated user input
}
/// Show custom message box
fn show_message_box(options: &MessageBoxOptions) -> MessageBoxResult {
// In WASM, this would create a custom modal dialog
println!("[{} - {}]: {}",
match options.box_type {
MessageBoxType::Info => "INFO",
MessageBoxType::Warning => "WARNING",
MessageBoxType::Error => "ERROR",
MessageBoxType::Question => "QUESTION",
MessageBoxType::Success => "SUCCESS",
},
options.title,
options.message
);
println!("Buttons: {:?}", options.buttons);
options.default_button
}
// 4. Common Message Box Helpers
/// Show information message
fn show_info(title: &str, message: &str) {
show_alert(title, message);
}
/// Show warning message
fn show_warning(title: &str, message: &str) {
let options = MessageBoxOptions::new(title, message)
.with_type(MessageBoxType::Warning);
show_message_box(&options);
}
/// Show error message
fn show_error(title: &str, message: &str) {
let options = MessageBoxOptions::new(title, message)
.with_type(MessageBoxType::Error);
show_message_box(&options);
}
/// Show success message
fn show_success(title: &str, message: &str) {
let options = MessageBoxOptions::new(title, message)
.with_type(MessageBoxType::Success);
show_message_box(&options);
}
/// Show question dialog
fn show_question(title: &str, message: &str) -> MessageBoxResult {
let options = MessageBoxOptions::new(title, message)
.with_type(MessageBoxType::Question)
.with_buttons(MessageBoxButtons::YesNo)
.with_default(MessageBoxResult::Yes);
show_message_box(&options)
}
/// Show confirmation dialog
fn show_confirmation(title: &str, message: &str) -> bool {
matches!(show_question(title, message), MessageBoxResult::Yes)
}
// 5. Progress Dialog
/// Progress dialog state
struct ProgressDialog {
title: String,
message: String,
progress: f64,
}
impl ProgressDialog {
fn new(title: &str, message: &str) -> Self {
ProgressDialog {
title: title.to_string(),
message: message.to_string(),
progress: 0.0,
}
}
fn set_message(&mut self, message: &str) {
self.message = message.to_string();
println!("[PROGRESS] {} - {} ({}%)", self.title, message, self.progress);
}
fn set_progress(&mut self, progress: f64) {
self.progress = progress.max(0.0).min(100.0);
println!("[PROGRESS] {} - {} ({}%)", self.title, self.message, self.progress);
}
fn increment(&mut self, amount: f64) {
self.set_progress(self.progress + amount);
}
fn close(self) {
println!("[PROGRESS] Closed: {}", self.title);
}
}
// 6. Input Dialog
/// Input dialog result
enum InputResult {
Text(String),
Cancelled,
}
/// Show input dialog
fn show_input_dialog(title: &str, message: &str) -> InputResult {
match show_prompt(title, message, "") {
Some(input) => InputResult::Text(input),
None => InputResult::Cancelled,
}
}
/// Show password input dialog
fn show_password_dialog(title: &str, message: &str) -> InputResult {
// In real implementation, this would use a password field
match show_prompt(title, message, "") {
Some(input) => InputResult::Text(input),
None => InputResult::Cancelled,
}
}
// 7. Selection Dialog
/// Show selection dialog
fn show_selection_dialog(title: &str, message: &str, options: &[&str]) -> Option<usize> {
println!("[SELECTION] {}: {}", title, message);
for (i, option) in options.iter().enumerate() {
println!(" {}. {}", i + 1, option);
}
Some(0) // Simulated selection
}
// 8. Toast Notifications
/// Toast notification type
#[derive(Debug, Clone, Copy)]
enum ToastType {
Info,
Success,
Warning,
Error,
}
/// Show toast notification
fn show_toast(message: &str, toast_type: ToastType) {
println!("[TOAST - {:?}] {}", toast_type, message);
}
/// Show info toast
fn toast_info(message: &str) {
show_toast(message, ToastType::Info);
}
/// Show success toast
fn toast_success(message: &str) {
show_toast(message, ToastType::Success);
}
/// Show warning toast
fn toast_warning(message: &str) {
show_toast(message, ToastType::Warning);
}
/// Show error toast
fn toast_error(message: &str) {
show_toast(message, ToastType::Error);
}
// 9. Dialog Builder
/// Builder for message box
struct MessageBoxBuilder {
options: MessageBoxOptions,
}
impl MessageBoxBuilder {
fn new(title: &str, message: &str) -> Self {
MessageBoxBuilder {
options: MessageBoxOptions::new(title, message),
}
}
fn info(mut self) -> Self {
self.options.box_type = MessageBoxType::Info;
self
}
fn warning(mut self) -> Self {
self.options.box_type = MessageBoxType::Warning;
self
}
fn error(mut self) -> Self {
self.options.box_type = MessageBoxType::Error;
self
}
fn question(mut self) -> Self {
self.options.box_type = MessageBoxType::Question;
self
}
fn success(mut self) -> Self {
self.options.box_type = MessageBoxType::Success;
self
}
fn ok_cancel(mut self) -> Self {
self.options.buttons = MessageBoxButtons::OkCancel;
self
}
fn yes_no(mut self) -> Self {
self.options.buttons = MessageBoxButtons::YesNo;
self
}
fn show(self) -> MessageBoxResult {
show_message_box(&self.options)
}
}
// 10. Batch Operations
/// Show multiple confirmations
fn show_multiple_confirmations(messages: &[(&str, &str)]) -> Vec<bool> {
messages.iter()
.map(|(title, msg)| show_confirmation(title, msg))
.collect()
}
/// Chain of dialogs
fn show_dialog_chain(dialogs: Vec<MessageBoxOptions>) -> Vec<MessageBoxResult> {
dialogs.iter()
.map(|options| show_message_box(options))
.collect()
}
// Usage Examples
fn main() {
println!("=== Web Rust Message Box Examples ===\n");
// 1. Simple alert
println!("--- 1. Simple Alert ---");
show_alert("Welcome", "Application started successfully");
// 2. Confirm dialog
println!("
--- 2. Confirm Dialog ---");
let confirmed = show_confirm("Confirm", "Do you want to continue?");
println!("User confirmed: {}", confirmed);
// 3. Prompt dialog
println!("
--- 3. Prompt Dialog ---");
match show_prompt("Input", "Enter your name:", "John") {
Some(name) => println!("User entered: {}", name),
None => println!("User cancelled"),
}
// 4. Different message types
println!("
--- 4. Message Types ---");
show_info("Info", "This is an information message");
show_warning("Warning", "This is a warning message");
show_error("Error", "This is an error message");
show_success("Success", "Operation completed successfully");
// 5. Question dialog
println!("
--- 5. Question Dialog ---");
let answer = show_question("Question", "Do you agree to the terms?");
println!("Answer: {:?}", answer);
// 6. Confirmation
println!("
--- 6. Confirmation ---");
let proceed = show_confirmation("Confirm Action", "Delete selected files?");
println!("Proceed: {}", proceed);
// 7. Progress dialog
println!("
--- 7. Progress Dialog ---");
let mut progress = ProgressDialog::new("Downloading", "Initializing...");
for i in 0..=10 {
progress.set_progress((i * 10) as f64);
progress.set_message(&format!("Downloading file {}...", i));
}
progress.close();
// 8. Toast notifications
println!("
--- 8. Toast Notifications ---");
toast_info("Application started");
toast_success("File saved successfully");
toast_warning("Low disk space");
toast_error("Connection failed");
// 9. Input dialog
println!("
--- 9. Input Dialog ---");
match show_input_dialog("Name", "Enter your name:") {
InputResult::Text(name) => println!("Name: {}", name),
InputResult::Cancelled => println!("Cancelled"),
}
// 10. Selection dialog
println!("
--- 10. Selection Dialog ---");
let options = vec!["Option 1", "Option 2", "Option 3"];
match show_selection_dialog("Choose", "Select an option:", &options) {
Some(index) => println!("Selected: {}", options[index]),
None => println!("Cancelled"),
}
// 11. Builder pattern
println!("
--- 11. Builder Pattern ---");
let result = MessageBoxBuilder::new("Delete", "Are you sure?")
.question()
.yes_no()
.show();
println!("Result: {:?}", result);
println!("
=== Note ===");
println!("For actual desktop message boxes in Rust, consider:");
println!("- Tauri: https://tauri.app/");
println!("- egui: https://github.com/emilk/egui");
println!("- native-dialog: https://github.com/babdul/national");
println!("
=== All Message Box Examples Completed ===");
}
💻 Diálogo de Archivos rust
🟡 intermediate
⭐⭐⭐
Abrir y guardar diálogos de archivos usando Web APIs (con WASM)
⏱️ 20 min
🏷️ rust, web, desktop features
Prerequisites:
Intermediate Rust, Understanding of Web APIs
// Web Rust File Dialog Examples
// File open/save dialogs using browser Web APIs
//
// This demonstrates file dialog functionality that would work in WebAssembly (WASM) context
//
// For actual desktop file dialogs, consider using:
// - Tauri (https://tauri.app/) for desktop apps
// - egui + rfd (https://github.com/PolyMeilex/rfd) for native dialogs
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
// 1. File Selection Result
/// Result of file selection
#[derive(Debug, Clone, Serialize, Deserialize)]
struct FileSelection {
name: String,
size: u64,
content_type: Option<String>,
}
// 2. File Dialog Simulation
// Note: In WASM, you would use JavaScript interop for actual file dialogs
/// Simulated file dialog options
#[derive(Debug, Clone)]
struct FileDialogOptions {
title: String,
filters: Vec<FileFilter>,
multi_select: bool,
directory: bool,
}
impl Default for FileDialogOptions {
fn default() -> Self {
FileDialogOptions {
title: "Select File".to_string(),
filters: Vec::new(),
multi_select: false,
directory: false,
}
}
}
/// File filter for dialog
#[derive(Debug, Clone)]
struct FileFilter {
name: String,
extensions: Vec<String>,
}
impl FileFilter {
fn new(name: &str, extensions: &[&str]) -> Self {
FileFilter {
name: name.to_string(),
extensions: extensions.iter().map(|s| s.to_string()).collect(),
}
}
}
// 3. File Dialog Functions (WASM-compatible)
/// Open file dialog (returns selected file paths)
/// In WASM, this would call JavaScript's File API
fn open_file_dialog(options: &FileDialogOptions) -> Result<Vec<PathBuf>, String> {
// Simulated implementation
// In real WASM, you would use wasm-bindgen with web-sys
let mut selected = Vec::new();
// This is a placeholder - actual implementation requires JS interop
if options.directory {
// Would use <input type="file" webkitdirectory>
} else if options.multi_select {
// Would use <input type="file" multiple>
} else {
// Would use <input type="file">
}
if selected.is_empty() {
Err("No file selected".to_string())
} else {
Ok(selected)
}
}
/// Save file dialog
fn save_file_dialog(options: &FileDialogOptions) -> Result<PathBuf, String> {
// In WASM, this would trigger browser download
Ok(PathBuf::from("saved_file.txt"))
}
// 4. File Reading
/// Read file content as text
fn read_file_text(path: &PathBuf) -> Result<String, String> {
std::fs::read_to_string(path).map_err(|e| e.to_string())
}
/// Read file content as bytes
fn read_file_bytes(path: &PathBuf) -> Result<Vec<u8>, String> {
std::fs::read(path).map_err(|e| e.to_string())
}
// 5. File Writing
/// Write text to file
fn write_file_text(path: &PathBuf, content: &str) -> Result<(), String> {
std::fs::write(path, content).map_err(|e| e.to_string())
}
/// Write bytes to file
fn write_file_bytes(path: &PathBuf, content: &[u8]) -> Result<(), String> {
std::fs::write(path, content).map_err(|e| e.to_string())
}
// 6. File Validation
/// Check if file exists
fn file_exists(path: &PathBuf) -> bool {
path.exists()
}
/// Get file metadata
fn get_file_info(path: &PathBuf) -> Result<FileSelection, String> {
let metadata = std::fs::metadata(path).map_err(|e| e.to_string())?;
let name = path.file_name()
.and_then(|n| n.to_str())
.unwrap_or("unknown")
.to_string();
Ok(FileSelection {
name,
size: metadata.len(),
content_type: None, // Would detect from extension
})
}
// 7. File Type Detection
/// Get file extension
fn get_file_extension(path: &PathBuf) -> Option<String> {
path.extension()
.and_then(|ext| ext.to_str())
.map(|s| s.to_string())
}
/// Get MIME type from extension
fn get_mime_type(path: &PathBuf) -> Option<&'static str> {
match get_file_extension(path)?.as_str() {
"txt" => Some("text/plain"),
"html" => Some("text/html"),
"css" => Some("text/css"),
"js" => Some("application/javascript"),
"json" => Some("application/json"),
"png" => Some("image/png"),
"jpg" | "jpeg" => Some("image/jpeg"),
"gif" => Some("image/gif"),
"pdf" => Some("application/pdf"),
"zip" => Some("application/zip"),
_ => Some("application/octet-stream"),
}
}
// 8. Common File Filters
/// Create image file filter
fn image_filter() -> FileFilter {
FileFilter::new("Images", &["png", "jpg", "jpeg", "gif", "bmp", "webp"])
}
/// Create text file filter
fn text_filter() -> FileFilter {
FileFilter::new("Text Files", &["txt", "md", "csv", "json", "xml"])
}
/// Create document file filter
fn document_filter() -> FileFilter {
FileFilter::new("Documents", &["pdf", "doc", "docx", "odt"])
}
/// Create all files filter
fn all_files_filter() -> FileFilter {
FileFilter::new("All Files", &["*"])
}
// 9. File Dialog Builder
/// Builder for file dialog options
struct FileDialogBuilder {
options: FileDialogOptions,
}
impl FileDialogBuilder {
fn new() -> Self {
FileDialogBuilder {
options: FileDialogOptions::default(),
}
}
fn title(mut self, title: &str) -> Self {
self.options.title = title.to_string();
self
}
fn add_filter(mut self, filter: FileFilter) -> Self {
self.options.filters.push(filter);
self
}
fn multi_select(mut self, multi: bool) -> Self {
self.options.multi_select = multi;
self
}
fn directory(mut self, dir: bool) -> Self {
self.options.directory = dir;
self
}
fn build(self) -> FileDialogOptions {
self.options
}
}
impl Default for FileDialogBuilder {
fn default() -> Self {
Self::new()
}
}
// 10. File Operations
/// Batch file reading
fn read_multiple_files(paths: &[PathBuf]) -> Vec<Result<String, String>> {
paths.iter().map(|p| read_file_text(p)).collect()
}
/// Batch file writing
fn write_multiple_files(data: &[(PathBuf, String)]) -> Vec<Result<(), String>> {
data.iter().map(|(path, content)| write_file_text(path, content)).collect()
}
// 11. File Dialog Result Processing
/// Process selected files
fn process_selected_files(paths: Vec<PathBuf>) -> Vec<FileSelection> {
paths.into_iter()
.filter_map(|path| {
if file_exists(&path) {
get_file_info(&path).ok()
} else {
None
}
})
.collect()
}
/// Validate file types
fn validate_file_type(path: &PathBuf, allowed_extensions: &[&str]) -> bool {
if let Some(ext) = get_file_extension(path) {
allowed_extensions.contains(&ext.as_str())
} else {
false
}
}
// Usage Examples
fn main() {
println!("=== Web Rust File Dialog Examples ===\n");
// 1. Create file dialog options
println!("--- 1. File Dialog Options ---");
let options = FileDialogBuilder::new()
.title("Open Image")
.add_filter(image_filter())
.add_filter(all_files_filter())
.multi_select(true)
.build();
println!("Dialog options: {:?}", options);
// 2. Simulate file dialog
println!("
--- 2. Open File Dialog ---");
match open_file_dialog(&options) {
Ok(paths) => println!("Selected {} files", paths.len()),
Err(e) => println!("Error: {}", e),
}
// 3. Save file dialog
println!("
--- 3. Save File Dialog ---");
let save_options = FileDialogBuilder::new()
.title("Save Document")
.add_filter(text_filter())
.build();
match save_file_dialog(&save_options) {
Ok(path) => println!("Save path: {:?}", path),
Err(e) => println!("Error: {}", e),
}
// 4. File filters
println!("
--- 4. File Filters ---");
println!("Image filter: {:?}", image_filter());
println!("Text filter: {:?}", text_filter());
println!("Document filter: {:?}", document_filter());
// 5. File type detection
println!("
--- 5. File Type Detection ---");
let test_path = PathBuf::from("test.png");
println!("Extension: {:?}", get_file_extension(&test_path));
println!("MIME type: {:?}", get_mime_type(&test_path));
// 6. File validation
println!("
--- 6. File Validation ---");
let allowed = vec!["png", "jpg", "jpeg"];
println!("Is valid image: {}", validate_file_type(&test_path, &allowed));
let invalid_path = PathBuf::from("test.txt");
println!("Is valid image: {}", validate_file_type(&invalid_path, &allowed));
println!("
=== Note ===");
println!("For actual desktop file dialogs in Rust, consider:");
println!("- Tauri: https://tauri.app/");
println!("- rfd: https://github.com/PolyMeilex/rfd");
println!("- egui: https://github.com/emilk/egui");
println!("
=== All File Dialog Examples Completed ===");
}
💻 Bandeja del Sistema rust
🔴 complex
⭐⭐⭐⭐
Iconos y menús de la bandeja del sistema (frameworks de escritorio)
⏱️ 30 min
🏷️ rust, web, desktop features
Prerequisites:
Advanced Rust, Desktop Framework Knowledge
// Web Rust System Tray Examples
// System tray icons and menu functionality
//
// This demonstrates system tray patterns. Note: System tray is NOT available in web browsers.
// For actual system tray functionality, you need desktop frameworks like:
// - Tauri (https://tauri.app/) - Desktop apps with web technologies
// - Tray-icon crate (https://github.com/tauri-apps/tray-icon) - Rust tray library
//
// The following examples show the API patterns for desktop framework integration
use std::sync::{Arc, Mutex};
// 1. Tray Icon Types
/// Tray icon state
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum TrayIconState {
Normal,
Active,
Disabled,
Busy,
}
/// Tray icon theme
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum TrayIconTheme {
Light,
Dark,
Auto,
}
// 2. Tray Menu Items
/// Menu item type
#[derive(Debug, Clone)]
enum MenuItemType {
Separator,
Action(String),
Checkbox(String, bool),
Submenu(String, Vec<MenuItem>),
}
/// Menu item
#[derive(Debug, Clone)]
struct MenuItem {
id: String,
item_type: MenuItemType,
enabled: bool,
visible: bool,
}
impl MenuItem {
fn separator() -> Self {
MenuItem {
id: format!("sep_{}", std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos()),
item_type: MenuItemType::Separator,
enabled: true,
visible: true,
}
}
fn action(id: &str, label: &str) -> Self {
MenuItem {
id: id.to_string(),
item_type: MenuItemType::Action(label.to_string()),
enabled: true,
visible: true,
}
}
fn checkbox(id: &str, label: &str, checked: bool) -> Self {
MenuItem {
id: id.to_string(),
item_type: MenuItemType::Checkbox(label.to_string(), checked),
enabled: true,
visible: true,
}
}
fn submenu(id: &str, label: &str, items: Vec<MenuItem>) -> Self {
MenuItem {
id: id.to_string(),
item_type: MenuItemType::Submenu(label.to_string(), items),
enabled: true,
visible: true,
}
}
fn set_enabled(mut self, enabled: bool) -> Self {
self.enabled = enabled;
self
}
fn set_visible(mut self, visible: bool) -> Self {
self.visible = visible;
self
}
}
// 3. Tray Icon Configuration
/// Tray icon configuration
#[derive(Debug, Clone)]
struct TrayIconConfig {
icon_path: String,
tooltip: String,
theme: TrayIconTheme,
state: TrayIconState,
}
impl TrayIconConfig {
fn new(icon_path: &str, tooltip: &str) -> Self {
TrayIconConfig {
icon_path: icon_path.to_string(),
tooltip: tooltip.to_string(),
theme: TrayIconTheme::Auto,
state: TrayIconState::Normal,
}
}
fn with_theme(mut self, theme: TrayIconTheme) -> Self {
self.theme = theme;
self
}
fn with_state(mut self, state: TrayIconState) -> Self {
self.state = state;
self
}
}
// 4. System Tray Implementation (Mock)
/// System tray (mock implementation for API demonstration)
struct SystemTray {
config: TrayIconConfig,
menu: Vec<MenuItem>,
on_click: Option<Box<dyn Fn()>>,
on_double_click: Option<Box<dyn Fn()>>,
}
impl SystemTray {
fn new(config: TrayIconConfig) -> Self {
SystemTray {
config,
menu: Vec::new(),
on_click: None,
on_double_click: None,
}
}
fn set_menu(&mut self, menu: Vec<MenuItem>) {
self.menu = menu;
println!("Tray menu updated with {} items", menu.len());
}
fn set_tooltip(&mut self, tooltip: &str) {
self.config.tooltip = tooltip.to_string();
println!("Tray tooltip updated: {}", tooltip);
}
fn set_icon(&mut self, icon_path: &str) {
self.config.icon_path = icon_path.to_string();
println!("Tray icon updated: {}", icon_path);
}
fn set_state(&mut self, state: TrayIconState) {
self.config.state = state;
println!("Tray state updated: {:?}", state);
}
fn show(&self) {
println!("Tray icon shown: {}", self.config.tooltip);
}
fn hide(&self) {
println!("Tray icon hidden");
}
fn on_click<F: Fn() + 'static>(mut self, callback: F) -> Self {
self.on_click = Some(Box::new(callback));
self
}
fn on_double_click<F: Fn() + 'static>(mut self, callback: F) -> Self {
self.on_double_click = Some(Box::new(callback));
self
}
fn handle_menu_action(&self, item_id: &str) {
println!("Menu action triggered: {}", item_id);
// Would dispatch to event handler
}
}
// 5. Tray Menu Builder
/// Builder for tray menu
struct TrayMenuBuilder {
items: Vec<MenuItem>,
}
impl TrayMenuBuilder {
fn new() -> Self {
TrayMenuBuilder {
items: Vec::new(),
}
}
fn add_item(mut self, item: MenuItem) -> Self {
self.items.push(item);
self
}
fn add_separator(mut self) -> Self {
self.items.push(MenuItem::separator());
self
}
fn add_action(mut self, id: &str, label: &str) -> Self {
self.items.push(MenuItem::action(id, label));
self
}
fn add_checkbox(mut self, id: &str, label: &str, checked: bool) -> Self {
self.items.push(MenuItem::checkbox(id, label, checked));
self
}
fn add_submenu(mut self, id: &str, label: &str, items: Vec<MenuItem>) -> Self {
self.items.push(MenuItem::submenu(id, label, items));
self
}
fn build(self) -> Vec<MenuItem> {
self.items
}
}
impl Default for TrayMenuBuilder {
fn default() -> Self {
Self::new()
}
}
// 6. Notification Handler
/// Tray notification
#[derive(Debug, Clone)]
struct TrayNotification {
title: String,
body: String,
icon: Option<String>,
timeout: Option<u32>,
}
impl TrayNotification {
fn new(title: &str, body: &str) -> Self {
TrayNotification {
title: title.to_string(),
body: body.to_string(),
icon: None,
timeout: None,
}
}
fn with_icon(mut self, icon: &str) -> Self {
self.icon = Some(icon.to_string());
self
}
fn with_timeout(mut self, seconds: u32) -> Self {
self.timeout = Some(seconds);
self
}
}
// 7. Tray State Manager
/// Manages tray icon state
struct TrayStateManager {
state: Arc<Mutex<TrayIconState>>,
}
impl TrayStateManager {
fn new() -> Self {
TrayStateManager {
state: Arc::new(Mutex::new(TrayIconState::Normal)),
}
}
fn set_state(&self, new_state: TrayIconState) {
let mut state = self.state.lock().unwrap();
*state = new_state;
println!("Tray state changed to: {:?}", new_state);
}
fn get_state(&self) -> TrayIconState {
*self.state.lock().unwrap()
}
}
// 8. Common Tray Menu Patterns
/// Create default application menu
fn create_app_menu() -> Vec<MenuItem> {
TrayMenuBuilder::new()
.add_action("show", "Show")
.add_action("hide", "Hide")
.add_separator()
.add_action("settings", "Settings")
.add_action("about", "About")
.add_separator()
.add_action("quit", "Quit")
.build()
}
/// Create status toggle menu
fn create_status_menu(is_active: bool) -> Vec<MenuItem> {
TrayMenuBuilder::new()
.add_checkbox("status", "Active", is_active)
.add_separator()
.add_action("refresh", "Refresh Status")
.add_separator()
.add_action("quit", "Quit")
.build()
}
/// Create media player menu
fn create_media_menu() -> Vec<MenuItem> {
TrayMenuBuilder::new()
.add_action("play_pause", "Play/Pause")
.add_action("next", "Next Track")
.add_action("prev", "Previous Track")
.add_separator()
.add_submenu("playlist", "Playlist", vec![
MenuItem::action("shuffle", "Shuffle"),
MenuItem::action("repeat", "Repeat"),
])
.add_separator()
.add_action("quit", "Quit")
.build()
}
// 9. Tray Event Handler
/// Tray events
#[derive(Debug, Clone)]
enum TrayEvent {
Click,
DoubleClick,
MenuAction(String),
BalloonClick,
}
/// Handle tray events
fn handle_tray_event(event: TrayEvent) {
match event {
TrayEvent::Click => println!("Tray icon clicked"),
TrayEvent::DoubleClick => println!("Tray icon double-clicked"),
TrayEvent::MenuAction(id) => println!("Menu action: {}", id),
TrayEvent::BalloonClick => println!("Balloon notification clicked"),
}
}
// 10. Dynamic Menu Updates
/// Update menu item dynamically
fn update_menu_item(menu: &mut Vec<MenuItem>, id: &str, updater: impl FnOnce(&mut MenuItem)) {
if let Some(item) = menu.iter_mut().find(|i| i.id == id) {
updater(item);
}
}
/// Toggle checkbox in menu
fn toggle_menu_checkbox(menu: &mut Vec<MenuItem>, id: &str) -> bool {
if let Some(item) = menu.iter_mut().find(|i| i.id == id) {
if let MenuItemType::Checkbox(label, checked) = &mut item.item_type {
*checked = !*checked;
return *checked;
}
}
false
}
// Usage Examples
fn main() {
println!("=== Web Rust System Tray Examples ===\n");
// 1. Create tray icon
println!("--- 1. Create Tray Icon ---");
let config = TrayIconConfig::new("icon.png", "My Application")
.with_state(TrayIconState::Normal);
let mut tray = SystemTray::new(config);
tray.show();
// 2. Set up menu
println!("
--- 2. Set Up Menu ---");
let menu = create_app_menu();
tray.set_menu(menu);
for item in &tray.menu {
println!(" - {:?}", item.item_type);
}
// 3. Update tooltip
println!("
--- 3. Update Tooltip ---");
tray.set_tooltip("Application running - 3 notifications");
// 4. Change state
println!("
--- 4. Change State ---");
tray.set_state(TrayIconState::Busy);
// 5. Menu builder
println!("
--- 5. Menu Builder ---");
let custom_menu = TrayMenuBuilder::new()
.add_action("file_open", "Open File")
.add_action("file_save", "Save File")
.add_separator()
.add_submenu("recent", "Recent Files", vec![
MenuItem::action("recent_1", "document1.txt"),
MenuItem::action("recent_2", "document2.txt"),
])
.build();
// 6. Status menu
println!("
--- 6. Status Menu ---");
let status_menu = create_status_menu(true);
println!("Status menu items: {}", status_menu.len());
// 7. Media menu
println!("
--- 7. Media Player Menu ---");
let media_menu = create_media_menu();
println!("Media menu items: {}", media_menu.len());
// 8. Menu updates
println!("
--- 8. Dynamic Menu Updates ---");
let mut menu = create_app_menu();
update_menu_item(&mut menu, "show", |item| {
item.enabled = false;
});
println!("Updated 'show' item: enabled={}",
menu.iter().find(|i| i.id == "show").map(|i| i.enabled).unwrap_or(false)
);
// 9. Toggle checkbox
println!("
--- 9. Toggle Checkbox ---");
let mut menu = create_status_menu(false);
let new_state = toggle_menu_checkbox(&mut menu, "status");
println!("Checkbox toggled to: {}", new_state);
// 10. Event handling
println!("
--- 10. Event Handling ---");
handle_tray_event(TrayEvent::Click);
handle_tray_event(TrayEvent::MenuAction("quit".to_string()));
// 11. Notification
println!("
--- 11. Notification ---");
let notification = TrayNotification::new("Update Available", "Version 2.0 is ready to install")
.with_icon("update-icon.png")
.with_timeout(10);
println!("Notification: {:?} - {:?}", notification.title, notification.body);
// 12. State manager
println!("
--- 12. State Manager ---");
let state_manager = TrayStateManager::new();
state_manager.set_state(TrayIconState::Active);
println!("Current state: {:?}", state_manager.get_state());
println!("
=== IMPORTANT NOTE ===");
println!("System tray functionality is NOT available in web browsers.");
println!("This code demonstrates API patterns for desktop frameworks.");
println!("");
println!("For actual system tray implementation in Rust:");
println!("- Tauri: https://tauri.app/ (recommended for web developers)");
println!("- tray-icon: https://github.com/tauri-apps/tray-icon");
println!("- egui: https://github.com/emilk/egui (with tray-icon)");
println!("
=== All System Tray Examples Completed ===");
}