chore: 初始化项目基础结构和资源文件
- 添加项目图标文件(app-icon.png、各平台图标) - 配置开发环境文件(.env、.nvmrc、.npmrc) - 添加静态资源文件(背景图片、字体、音频) - 初始化Tauri后端结构(build.rs、main.rs、模块文件) - 配置前端项目结构(TypeScript、Vue组件、样式) - 添加Node.js API服务基础结构 - 配置构建和开发工具(vite、prettier、gitignore)
This commit is contained in:
218
src-tauri/src/window/create_popup_window.rs
Normal file
218
src-tauri/src/window/create_popup_window.rs
Normal file
@ -0,0 +1,218 @@
|
||||
use crate::constants::window::*;
|
||||
use crate::window::{
|
||||
derive::{PopupLocation, PopupSize, TargetLocation},
|
||||
util::get_monitor_for_window,
|
||||
WindowLabel,
|
||||
};
|
||||
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();
|
||||
}
|
||||
|
||||
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)
|
||||
.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,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user