diff --git a/frontend/src/views/CaptureOverlay.vue b/frontend/src/views/CaptureOverlay.vue index 0b28a3c..633b75a 100644 --- a/frontend/src/views/CaptureOverlay.vue +++ b/frontend/src/views/CaptureOverlay.vue @@ -24,7 +24,8 @@ interface Rect { h: number } -type Tool = 'pen' | 'rect' | 'ellipse' | 'text' +type Tool = 'pen' | 'rect' | 'ellipse' | 'text' | 'mosaic-brush' | 'mosaic-rect' +type MosaicMode = 'brush' | 'rect' interface Point { x: number y: number @@ -77,6 +78,8 @@ const activeTool = ref('pen') const activeColor = ref('#ef4444') const activeStrokeWidth = ref(3) const activeFontSize = ref(20) +const mosaicMode = ref('brush') +const mosaicBrushWidth = ref(24) const textDraft = ref<{ point: Point value: string @@ -104,6 +107,7 @@ const textDragOriginalPoint = ref(null) const DEFAULT_TEXT_FONT_SIZE = 20 const STROKE_WIDTHS = [2, 4, 6] +const MOSAIC_WIDTHS = [16, 24, 36, 52] const FONT_SIZES = [16, 20, 28, 36] const colors = [ @@ -146,17 +150,18 @@ const sizeLabel = computed(() => { return `${Math.round(rect.value.w)} × ${Math.round(rect.value.h)}` }) -const MARK_TOOLBAR_W = 178 +const MARK_TOOLBAR_W = 212 const ACTION_TOOLBAR_W = 288 const TOOLBAR_GROUP_GAP = 8 -const toolOrder: Tool[] = ['pen', 'rect', 'ellipse', 'text'] +const toolOrder: Tool[] = ['pen', 'rect', 'ellipse', 'text', 'mosaic-brush', 'mosaic-rect'] const toolSettingsPos = computed(() => { if (!leftToolbarPos.value || !rect.value || !activeTool.value) return null - const menuW = activeTool.value === 'text' ? 462 : 398 + const isMosaic = activeTool.value.startsWith('mosaic-') + const menuW = isMosaic ? (mosaicMode.value === 'brush' ? 328 : 112) : activeTool.value === 'text' ? 462 : 398 const menuH = 58 - const buttonIndex = toolOrder.indexOf(activeTool.value) + const buttonIndex = isMosaic ? 4 : toolOrder.indexOf(activeTool.value) const buttonCenter = 4 + buttonIndex * 34 + 14 let x = leftToolbarPos.value.x let y = leftToolbarPos.value.y + 44 @@ -432,7 +437,7 @@ function onSelectionMouseDown(e: MouseEvent) { draftAnnotation.value = { tool: activeTool.value, color: activeColor.value, - strokeWidth: activeStrokeWidth.value, + strokeWidth: activeTool.value === 'mosaic-brush' ? mosaicBrushWidth.value : activeStrokeWidth.value, points: [local], } } @@ -466,7 +471,7 @@ function onMouseMove(e: MouseEvent) { annotation.points[0] = clampTextLocalPoint(next, annotation) } } else if (dragMode.value === 'annotating' && draftAnnotation.value) { - if (activeTool.value === 'pen') { + if (activeTool.value === 'pen' || activeTool.value === 'mosaic-brush') { draftAnnotation.value.points.push(localPoint(p)) } else { draftAnnotation.value.points = [ @@ -524,6 +529,19 @@ function selectTool(tool: Tool) { activeTool.value = tool } +function selectMosaic() { + activeTool.value = mosaicMode.value === 'brush' ? 'mosaic-brush' : 'mosaic-rect' +} + +function chooseMosaicMode(mode: MosaicMode) { + mosaicMode.value = mode + selectMosaic() +} + +function chooseMosaicWidth(width: number) { + mosaicBrushWidth.value = width +} + function chooseColor(color: string) { activeColor.value = color if (textDraft.value) { @@ -748,6 +766,13 @@ onUnmounted(() => { :viewBox="`0 0 ${width} ${height}`" preserveAspectRatio="none" > + + + + + + + { {{ annotation.text }} + + @@ -922,6 +966,21 @@ onUnmounted(() => { + -
-
+
+