- 清理大量废弃的 barrel 导出文件,移除冗余的中间导出层 - 修复所有相对路径导入错误,统一调整为扁平化模块引用 - 更新多平台 pubspec 版本号与依赖库版本 - 补充后端功能问题管理后台与脚本工具 - 调整部分页面的快捷方式文案适配新功能 - 更新部分翻译覆盖率与API文档
167 lines
4.0 KiB
Dart
167 lines
4.0 KiB
Dart
// ============================================================
|
|
// 闲言APP — 智能对齐吸附辅助类
|
|
// 创建时间: 2026-04-20
|
|
// 更新时间: 2026-06-12
|
|
// 作用: 拖拽时自动吸附到边缘/中心线/其他图层边界
|
|
// 上次更新: 从 utils/ 子目录上移至 editor/ 目录
|
|
// ============================================================
|
|
|
|
import 'package:xianyan/editor/models/editor_models.dart';
|
|
|
|
/// 图层矩形 (统一表示)
|
|
class LayerRect {
|
|
const LayerRect({
|
|
required this.x,
|
|
required this.y,
|
|
required this.width,
|
|
required this.height,
|
|
});
|
|
|
|
final double x;
|
|
final double y;
|
|
final double width;
|
|
final double height;
|
|
|
|
double get centerX => x + width / 2;
|
|
double get centerY => y + height / 2;
|
|
double get right => x + width;
|
|
double get bottom => y + height;
|
|
}
|
|
|
|
/// 从 TextLayer 估算矩形
|
|
LayerRect textLayerRect(TextLayer l, double canvasW, double canvasH) {
|
|
final w = l.fontSize * l.text.length * 0.6 * l.scale;
|
|
final h = l.fontSize * l.lineHeight * l.scale;
|
|
return LayerRect(
|
|
x: l.offsetX * canvasW,
|
|
y: l.offsetY * canvasH,
|
|
width: w,
|
|
height: h,
|
|
);
|
|
}
|
|
|
|
/// 从 GlassCardLayer 计算矩形
|
|
LayerRect glassLayerRect(GlassCardLayer l) {
|
|
return LayerRect(
|
|
x: l.offsetX,
|
|
y: l.offsetY,
|
|
width: l.width * l.scale,
|
|
height: l.height * l.scale,
|
|
);
|
|
}
|
|
|
|
/// 从 StickerLayer 计算矩形
|
|
LayerRect stickerLayerRect(StickerLayer l) {
|
|
return LayerRect(
|
|
x: l.offsetX,
|
|
y: l.offsetY,
|
|
width: l.size * l.scale,
|
|
height: l.size * l.scale,
|
|
);
|
|
}
|
|
|
|
/// 吸附结果
|
|
class SnapResult {
|
|
const SnapResult({
|
|
required this.snappedX,
|
|
required this.snappedY,
|
|
this.guidesX = const [],
|
|
this.guidesY = const [],
|
|
});
|
|
|
|
final double snappedX;
|
|
final double snappedY;
|
|
final List<double> guidesX;
|
|
final List<double> guidesY;
|
|
|
|
bool get isSnapped => guidesX.isNotEmpty || guidesY.isNotEmpty;
|
|
}
|
|
|
|
/// 智能对齐辅助类
|
|
class SnapHelper {
|
|
static const double snapThreshold = 12.0;
|
|
|
|
/// 计算吸附后的偏移量 (支持所有图层类型)
|
|
static SnapResult calculateSnap({
|
|
required double rawX,
|
|
required double rawY,
|
|
required double layerW,
|
|
required double layerH,
|
|
required double canvasW,
|
|
required double canvasH,
|
|
required List<LayerRect> otherLayers,
|
|
}) {
|
|
final guidesX = <double>[];
|
|
final guidesY = <double>[];
|
|
|
|
double snappedX = rawX;
|
|
double snappedY = rawY;
|
|
|
|
final xTargets = <double>[
|
|
0.0,
|
|
(canvasW - layerW) / 2,
|
|
canvasW - layerW,
|
|
];
|
|
for (final l in otherLayers) {
|
|
xTargets.addAll([l.x, l.centerX, l.right]);
|
|
}
|
|
|
|
for (final target in xTargets) {
|
|
if ((rawX - target).abs() < snapThreshold) {
|
|
snappedX = target;
|
|
guidesX.add(target + layerW / 2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
final yTargets = <double>[
|
|
0.0,
|
|
(canvasH - layerH) / 2,
|
|
canvasH - layerH,
|
|
];
|
|
for (final l in otherLayers) {
|
|
yTargets.addAll([l.y, l.centerY, l.bottom]);
|
|
}
|
|
|
|
for (final target in yTargets) {
|
|
if ((rawY - target).abs() < snapThreshold) {
|
|
snappedY = target;
|
|
guidesY.add(target + layerH / 2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return SnapResult(
|
|
snappedX: snappedX,
|
|
snappedY: snappedY,
|
|
guidesX: guidesX,
|
|
guidesY: guidesY,
|
|
);
|
|
}
|
|
|
|
/// 从画布模型构建所有图层矩形列表 (排除指定ID)
|
|
static List<LayerRect> buildLayerRects(
|
|
QuoteCanvasModel canvas, {
|
|
String? excludeId,
|
|
}) {
|
|
final rects = <LayerRect>[];
|
|
final cw = canvas.canvasWidth;
|
|
final ch = canvas.canvasHeight;
|
|
|
|
for (final l in canvas.textLayers) {
|
|
if (l.id == excludeId || !l.visible) continue;
|
|
rects.add(textLayerRect(l, cw, ch));
|
|
}
|
|
for (final l in canvas.glassCardLayers) {
|
|
if (l.id == excludeId || !l.visible) continue;
|
|
rects.add(glassLayerRect(l));
|
|
}
|
|
for (final l in canvas.stickerLayers) {
|
|
if (l.id == excludeId || !l.visible) continue;
|
|
rects.add(stickerLayerRect(l));
|
|
}
|
|
|
|
return rects;
|
|
}
|
|
}
|