Files
tauri-meeting/src-tauri/src/window/create_popup_window.rs

216 lines
7.7 KiB
Rust
Raw Normal View History

use crate::constants::window::*;
use crate::window::{
WindowLabel,
derive::{PopupLocation, PopupSize, TargetLocation},
util::get_monitor_for_window,
};
use tauri::{AppHandle, Manager, Runtime, WebviewUrl, WebviewWindowBuilder};
/// 创建弹出框窗口(内部实现)
pub async fn create_popup_window_impl<R: Runtime>(app: &AppHandle<R>, target: &TargetLocation, placement: &str) -> Result<(), String> {
// 获取屏幕尺寸优先为main窗口所在屏幕主窗口没有打开时才找主屏幕
let monitor: tauri::Monitor = get_monitor_for_window(app)?;
// 使用动态计算的弹出窗口尺寸
let popup_size = calculate_popup_size_sync();
let page_size = monitor.size().to_logical(monitor.scale_factor());
// 计算弹出框位置和大小
let popup_location = calculate_placement(target, &popup_size, placement, &page_size).await?;
let label = WindowLabel::POPUP.as_ref();
// 检查是否已经存在名为"popup"的窗口
if let Some(popup_window) = app.get_webview_window(label) {
// 如果窗口已存在,直接关闭它
let _ = popup_window.close();
}
log::info!("创建弹出框窗口: {:?}", popup_location);
let url = format!("popup-window.html?placement={}", popup_location.placement); // 创建弹出框窗口
WebviewWindowBuilder::new(app, label, WebviewUrl::App(url.into()))
.title("弹出框")
.inner_size(popup_location.width as f64, popup_location.height as f64)
.position(popup_location.x as f64, popup_location.y as f64)
.resizable(false)
.transparent(true)
.decorations(false)
.shadow(false)
.focusable(true)
.focused(true)
.accept_first_mouse(true)
.skip_taskbar(true)
.always_on_top(true)
.visible(true)
.build()
.map_err(|e| format!("创建弹出框窗口失败: {}", e))?;
Ok(())
}
/// 根据用户登录状态和课程选择情况动态计算弹出窗口高度
pub fn calculate_popup_size_sync() -> PopupSize {
// 默认基础项目数
let item_num = 3;
// 根据项目数计算高度每个项目40像素加上边距2像素
let popup_height = 40 * item_num + 2;
let popup_width = 180;
// 返回计算得到的弹出窗口尺寸
PopupSize {
width: popup_width,
height: popup_height,
}
}
/// 计算弹出框位置
pub async fn calculate_placement(target: &TargetLocation, popup_size: &PopupSize, placement: &str, page_size: &tauri::LogicalSize<i32>) -> Result<PopupLocation, String> {
let margin = 12; // 箭头距离触发元素的距离
let mar = 12; // 距离屏幕边缘的最小距离
let page_width = page_size.width;
let page_height = page_size.height;
// 点击dom宽高
let target_width = target.width;
let target_height = target.height;
// 点击dom右上角的坐标
let target_x = target.x;
let target_y = target.y;
// 点击dom中心点坐标
let center_x = target_x + (target_width / 2) as i32;
let center_y = target_y + (target_height / 2) as i32;
// 弹出框的宽高
let bubble_width = popup_size.width;
let bubble_height = popup_size.height;
// 如果placement为"center",则直接返回屏幕中央位置
if placement == PLACEMENT_CENTER {
return Ok(calculate_center_position(popup_size, page_size));
}
// 上面足够
let top_enough = bubble_height as i32 + margin + mar < target_y;
// 下面足够
let bottom_enough = (target_y + target_height as i32 + bubble_height as i32 + margin + mar) < page_height;
// 左面足够
let left_enough = target_x - bubble_width as i32 - margin - mar >= 0;
// 右面足够
let right_enough = target_x + target_width as i32 + bubble_width as i32 + margin + mar < page_width;
// 屏幕宽度足够
let width_enough = page_width > bubble_width as i32 + mar * 2;
// 屏幕高度足够
let height_enough = page_height > bubble_height as i32 + mar * 2;
if (placement == PLACEMENT_AUTO || placement == PLACEMENT_TOP) && top_enough && width_enough {
get_top_bottom_placement(PLACEMENT_TOP, target, popup_size, margin, mar, center_x, page_width)
} else if (placement == PLACEMENT_AUTO || placement == PLACEMENT_BOTTOM) && bottom_enough && width_enough {
get_top_bottom_placement(PLACEMENT_BOTTOM, target, popup_size, margin, mar, center_x, page_width)
} else if (placement == PLACEMENT_AUTO || placement == PLACEMENT_LEFT) && left_enough && height_enough {
get_left_right_placement(PLACEMENT_LEFT, target, popup_size, margin, mar, center_y, page_height)
} else if (placement == PLACEMENT_AUTO || placement == PLACEMENT_RIGHT) && right_enough && height_enough {
get_left_right_placement(PLACEMENT_RIGHT, target, popup_size, margin, mar, center_y, page_height)
} else {
let popup_y = center_y + (target_height as i32) / 2 + margin;
Ok(PopupLocation {
enough_show: false,
placement: PLACEMENT_CENTER.to_string(),
x: 0,
y: popup_y,
width: popup_size.width,
height: popup_size.height,
})
}
}
/// 计算屏幕中央位置
pub fn calculate_center_position(popup_size: &PopupSize, page_size: &tauri::LogicalSize<i32>) -> PopupLocation {
let page_width = page_size.width;
let page_height = page_size.height;
let popup_x = (page_width - popup_size.width as i32) / 2;
let popup_y = (page_height - popup_size.height as i32) / 2;
PopupLocation {
enough_show: true,
placement: PLACEMENT_CENTER.to_string(),
x: popup_x,
y: popup_y,
width: popup_size.width,
height: popup_size.height,
}
}
/// 上或者下足够并且宽度也足够时的位置计算
fn get_top_bottom_placement(
placement: &str,
target: &TargetLocation,
popup_size: &PopupSize,
margin: i32,
mar: i32,
center_x: i32,
page_width: i32,
) -> Result<PopupLocation, String> {
let popup_y = if placement == "bottom" {
target.y + target.height as i32 + margin
} else {
target.y - popup_size.height as i32 - margin
};
let right_x = center_x - (popup_size.width as i32) / 2;
let left_x = center_x + (popup_size.width as i32) / 2;
let mut popup_x = mar;
if right_x >= mar && page_width - left_x >= mar {
popup_x = right_x;
} else if page_width - left_x >= mar {
popup_x = mar;
} else if right_x >= mar {
popup_x = page_width - popup_size.width as i32 - mar;
}
Ok(PopupLocation {
enough_show: true,
placement: placement.to_string(),
y: popup_y,
x: popup_x,
width: popup_size.width,
height: popup_size.height,
})
}
/// 左或者右足够并且高度也足够时的位置计算
fn get_left_right_placement(
placement: &str,
target: &TargetLocation,
popup_size: &PopupSize,
margin: i32,
mar: i32,
center_y: i32,
page_height: i32,
) -> Result<PopupLocation, String> {
let popup_x = if placement == "left" {
target.x - popup_size.width as i32 - margin
} else {
target.x + target.width as i32 + margin
};
let top_y = center_y - (popup_size.height as i32) / 2;
let bottom_y = center_y + (popup_size.height as i32) / 2;
let popup_y = if top_y >= mar && page_height - bottom_y >= mar {
// 水平居中
top_y
} else if page_height - bottom_y >= mar {
mar
} else {
page_height - popup_size.height as i32 - mar
};
Ok(PopupLocation {
enough_show: true,
placement: placement.to_string(),
y: popup_y,
x: popup_x,
width: popup_size.width,
height: popup_size.height,
})
}