Skip to content

Commit

Permalink
refactor: avoid using macro where unnecessary (#376)
Browse files Browse the repository at this point in the history
  • Loading branch information
Charlie-XIAO authored Feb 1, 2025
1 parent 7168a54 commit 2276d46
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 136 deletions.
113 changes: 50 additions & 63 deletions crates/deskulpt-core/src/states/canvas_click_through.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,82 +17,69 @@ use crate::events::{EventsExt, ShowToastPayload};
struct CanvasClickThroughState<R: Runtime>(Mutex<(bool, Option<MenuItem<R>>)>);

/// Extension trait for operations on canvas click-through state.
pub trait StatesExtCanvasClickThrough<R: Runtime> {
pub trait StatesExtCanvasClickThrough<R: Runtime>: Manager<R> + EventsExt<R> {
/// Initialize state management for whether the canvas is click-through.
///
/// The canvas is click-through by default.
fn manage_canvas_click_through(&self);
fn manage_canvas_click_through(&self) {
self.manage(CanvasClickThroughState::<R>(Mutex::new((true, None))));
}

/// Set the menu item for toggling the canvas click-through state.
fn set_canvas_click_through_menu_item(&self, menu_item: &MenuItem<R>);
fn set_canvas_click_through_menu_item(&self, menu_item: &MenuItem<R>) {
let state = self.state::<CanvasClickThroughState<R>>();
let mut canvas_click_through = state.0.lock().unwrap();

// Cloning works because menu items are behind shared references
canvas_click_through.1 = Some(menu_item.clone());
}

/// Toggle the click-through state of the canvas window.
///
/// This will also update the menu item text and show a toast message on the
/// canvas if possible.
fn toggle_canvas_click_through(&self) -> Result<()>;
}

/// Shared implementation of [`StatesExtCanvasClickThrough`].
macro_rules! shared_impl {
($app: ty) => {
impl<R: Runtime> StatesExtCanvasClickThrough<R> for $app {
fn manage_canvas_click_through(&self) {
self.manage(CanvasClickThroughState::<R>(Mutex::new((true, None))));
fn toggle_canvas_click_through(&self) -> Result<()> {
let canvas = self
.get_webview_window("canvas")
.expect("Canvas window not found");

let state = self.state::<CanvasClickThroughState<R>>();
let mut canvas_click_through = state.0.lock().unwrap();
let prev_click_through = canvas_click_through.0;
canvas.set_ignore_cursor_events(!prev_click_through)?;
canvas_click_through.0 = !prev_click_through;

let (menu_item_text, toast_message) = if prev_click_through {
// If the canvas is toggled to not click-through, try to regain
// focus to avoid flickering on the first click
if let Err(e) = canvas.set_focus() {
eprintln!("Failed to gain focus on canvas: {}", e);
}

fn set_canvas_click_through_menu_item(&self, menu_item: &MenuItem<R>) {
let state = self.state::<CanvasClickThroughState<R>>();
let mut canvas_click_through = state.0.lock().unwrap();

// Cloning works because menu items are behind shared references
canvas_click_through.1 = Some(menu_item.clone());
("Sink", "Canvas floated.")
} else {
("Float", "Canvas sunk.")
};

// Update menu item text if it exists
if let Some(menu_item) = canvas_click_through.1.as_ref() {
if let Err(e) = menu_item.set_text(menu_item_text) {
eprintln!(
"Failed to update menu item for toggling canvas click-through: {}",
e
);
}
}

fn toggle_canvas_click_through(&self) -> Result<()> {
let canvas = self
.get_webview_window("canvas")
.expect("Canvas window not found");

let state = self.state::<CanvasClickThroughState<R>>();
let mut canvas_click_through = state.0.lock().unwrap();
let prev_click_through = canvas_click_through.0;
canvas.set_ignore_cursor_events(!prev_click_through)?;
canvas_click_through.0 = !prev_click_through;

let (menu_item_text, toast_message) = if prev_click_through {
// If the canvas is toggled to not click-through, try to regain
// focus to avoid flickering on the first click
if let Err(e) = canvas.set_focus() {
eprintln!("Failed to gain focus on canvas: {}", e);
}
("Sink", "Canvas floated.")
} else {
("Float", "Canvas sunk.")
};

// Update menu item text if it exists
if let Some(menu_item) = canvas_click_through.1.as_ref() {
if let Err(e) = menu_item.set_text(menu_item_text) {
eprintln!(
"Failed to update menu item for toggling canvas click-through: {}",
e
);
}
}

// Show a toast message on the canvas
if let Err(e) = self
.emit_show_toast_to_canvas(ShowToastPayload::Success(toast_message.to_string()))
{
eprintln!("Failed to emit show-toast to canvas: {}", e);
}

Ok(())
}
// Show a toast message on the canvas
if let Err(e) =
self.emit_show_toast_to_canvas(ShowToastPayload::Success(toast_message.to_string()))
{
eprintln!("Failed to emit show-toast to canvas: {}", e);
}
};

Ok(())
}
}

shared_impl!(App<R>);
shared_impl!(AppHandle<R>);
impl<R: Runtime> StatesExtCanvasClickThrough<R> for App<R> {}
impl<R: Runtime> StatesExtCanvasClickThrough<R> for AppHandle<R> {}
53 changes: 18 additions & 35 deletions crates/deskulpt-core/src/states/widget_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,55 +11,38 @@ use crate::config::WidgetCollection;
struct WidgetCollectionState(RwLock<WidgetCollection>);

/// Extension trait for operations on widget collection state.
pub trait StatesExtWidgetCollection {
pub trait StatesExtWidgetCollection<R: Runtime>: Manager<R> {
/// Initialize state management for the widget collection.
fn manage_widget_collection(&self);
fn manage_widget_collection(&self) {
self.manage(WidgetCollectionState::default());
}

/// Provide reference to the widget collection within a closure.
///
/// This will lock the widget collection state. The return value of the
/// closure will be propagated.
fn with_widget_collection<F, T>(&self, f: F) -> T
where
F: FnOnce(&WidgetCollection) -> T;
F: FnOnce(&WidgetCollection) -> T,
{
let state = self.state::<WidgetCollectionState>();
let widget_collection = state.0.read().unwrap();
f(&widget_collection)
}

/// Provide mutable reference to the widget collection within a closure.
///
/// This will lock the widget collection state. The return value of the
/// closure will be propagated.
fn with_widget_collection_mut<F, T>(&self, f: F) -> T
where
F: FnOnce(&mut WidgetCollection) -> T;
F: FnOnce(&mut WidgetCollection) -> T,
{
let state = self.state::<WidgetCollectionState>();
let mut widget_collection = state.0.write().unwrap();
f(&mut widget_collection)
}
}

/// Shared implementation of [`StatesExtWidgetCollection`].
macro_rules! shared_impl {
($app: ty) => {
impl<R: Runtime> StatesExtWidgetCollection for $app {
fn manage_widget_collection(&self) {
self.manage(WidgetCollectionState::default());
}

fn with_widget_collection<F, T>(&self, f: F) -> T
where
F: FnOnce(&WidgetCollection) -> T,
{
let state = self.state::<WidgetCollectionState>();
let widget_collection = state.0.read().unwrap();
f(&widget_collection)
}

fn with_widget_collection_mut<F, T>(&self, f: F) -> T
where
F: FnOnce(&mut WidgetCollection) -> T,
{
let state = self.state::<WidgetCollectionState>();
let mut widget_collection = state.0.write().unwrap();
f(&mut widget_collection)
}
}
};
}

shared_impl!(App<R>);
shared_impl!(AppHandle<R>);
impl<R: Runtime> StatesExtWidgetCollection<R> for App<R> {}
impl<R: Runtime> StatesExtWidgetCollection<R> for AppHandle<R> {}
69 changes: 31 additions & 38 deletions crates/deskulpt-core/src/tray.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,57 +6,50 @@ use anyhow::Result;
use tauri::image::Image;
use tauri::menu::{MenuBuilder, MenuEvent, MenuItemBuilder};
use tauri::tray::{MouseButton, MouseButtonState, TrayIcon, TrayIconBuilder, TrayIconEvent};
use tauri::{App, AppHandle, Runtime};
use tauri::{App, AppHandle, Manager, Runtime};
use tokio::time::sleep;

use crate::events::EventsExt;
use crate::states::StatesExtCanvasClickThrough;
use crate::window::WindowExt;

/// Extention trait for system tray-related operations.
pub trait TrayExt {
pub trait TrayExt<R: Runtime>: Manager<R> + StatesExtCanvasClickThrough<R> {
/// Create the system tray.
fn create_tray(&self, icon: Image) -> Result<()>;
}

/// Shared implementation of [`TrayExt`].
macro_rules! shared_impl {
($app: ty) => {
impl<R: Runtime> TrayExt for $app {
fn create_tray(&self, icon: Image) -> Result<()> {
// Store the menu item for toggling canvas click-through
let menu_item_toggle =
MenuItemBuilder::with_id("tray-toggle", "Float").build(self)?;
self.set_canvas_click_through_menu_item(&menu_item_toggle);
fn create_tray(&self, icon: Image) -> Result<()>
where
Self: Sized,
{
// Store the menu item for toggling canvas click-through
let menu_item_toggle = MenuItemBuilder::with_id("tray-toggle", "Float").build(self)?;
self.set_canvas_click_through_menu_item(&menu_item_toggle);

// Build the system tray menu
let tray_menu = MenuBuilder::new(self)
.items(&[
&menu_item_toggle,
&MenuItemBuilder::with_id("tray-manage", "Manage").build(self)?,
&MenuItemBuilder::with_id("tray-exit", "Exit").build(self)?,
])
.build()?;
// Build the system tray menu
let tray_menu = MenuBuilder::new(self)
.items(&[
&menu_item_toggle,
&MenuItemBuilder::with_id("tray-manage", "Manage").build(self)?,
&MenuItemBuilder::with_id("tray-exit", "Exit").build(self)?,
])
.build()?;

// Build the system tray icon
TrayIconBuilder::with_id("tray")
.icon(icon)
.icon_as_template(true)
.show_menu_on_left_click(false)
.tooltip("Deskulpt")
.menu(&tray_menu)
.on_menu_event(on_menu_event)
.on_tray_icon_event(on_tray_icon_event)
.build(self)?;
// Build the system tray icon
TrayIconBuilder::with_id("tray")
.icon(icon)
.icon_as_template(true)
.show_menu_on_left_click(false)
.tooltip("Deskulpt")
.menu(&tray_menu)
.on_menu_event(on_menu_event)
.on_tray_icon_event(on_tray_icon_event)
.build(self)?;

Ok(())
}
}
};
Ok(())
}
}

shared_impl!(App<R>);
shared_impl!(AppHandle<R>);
impl<R: Runtime> TrayExt<R> for App<R> {}
impl<R: Runtime> TrayExt<R> for AppHandle<R> {}

/// Handler for system tray menu events.
///
Expand Down

0 comments on commit 2276d46

Please sign in to comment.