using ComPDFKit.Import; using ComPDFKit.PDFAnnotation; using ComPDFKit.PDFAnnotation.Form; using ComPDFKit.Tool.DrawTool; using ComPDFKit.Tool.Help; using ComPDFKit.Tool.UndoManger; using ComPDFKitViewer; using ComPDFKitViewer.BaseObject; using ComPDFKitViewer.Helper; using ComPDFKitViewer.Layer; using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Input; using System.Windows.Media; namespace ComPDFKit.Tool { public partial class CPDFViewerTool { private class AnnotSelectAreaData { public Point HitAreaPos { get; set; } public Point MoveAreaPos { get; set; } public Rect HitAreaBound { get; set; } public int HitPageIndex { get; set; } = -1; } private int AnnotSelectorIndex { get; set; } = -1; private AnnotSelector Selector { get; set; } private AnnotSelectAreaData AreaDrawData { get; set; } = new AnnotSelectAreaData(); private AnnotSelectAreaData AreaMoveData { get; set; } = new AnnotSelectAreaData(); private bool DrawSelect { get; set; } = true; private bool AllowMultiSelect { get; set; } private bool AllowAreaSelect { get; set; } private bool IsMoved { get; set; } = false; private Point OffsetPos { get; set; } = new Point(0, 0); private List AnnotParamList { get; set; } = new List(); private void AnnotSelectInsert() { Selector = new AnnotSelector(); Selector.PDFViewer = PDFViewer; int annotViewindex = PDFViewer.GetMaxViewIndex(); PDFViewer.InsertView(annotViewindex, Selector); AnnotSelectorIndex = Selector.GetResTag(); } private void AnnotSelectUpdate() { if (!AllowMultiSelect) { return; } if (Selector == null || Selector.SelectAnnots == null) { return; } if (PDFViewer == null || PDFViewer.CurrentRenderFrame == null) { Selector?.ClearItem(); Selector?.CleanDraw(); return; } List annotDatas = PDFViewer.CurrentRenderFrame.AnnotDataList; if (annotDatas == null || annotDatas.Count == 0) { return; } foreach (AnnotData checkItem in Selector.SelectAnnots.ToList()) { AnnotData saveItem = annotDatas.Where(x => x.PageIndex == checkItem.PageIndex && x.AnnotIndex == checkItem.AnnotIndex).FirstOrDefault(); if (saveItem != null) { Selector.RemoveItem(checkItem); Selector.AddItem(saveItem); } } } public void SetAnnotAllowMultiSelect(bool isAllow) { AllowMultiSelect = isAllow; AllowAreaSelect = isAllow; } private void AnnotSelectDraw() { if (!AllowMultiSelect) { return; } if (DrawSelect == false) { return; } if (Selector?.GetSelectCount() > 1) { Selector?.Draw(); return; } Selector?.CleanDraw(); } private void AnnotSelectAddItem(AnnotData annotData, bool clean = true) { if (!AllowMultiSelect || annotData == null) { return; } if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) { if (Selector?.HasItem(annotData) == true) { if (Selector?.GetSelectCount() != 1) { Selector?.RemoveItem(annotData); } } else { Selector?.AddItem(annotData); } return; } if (clean) { Selector?.ClearItem(); Selector?.AddItem(annotData); } } private void AnnotSelectAreaHit() { if (!AllowMultiSelect) { return; } AreaDrawData.HitPageIndex = -1; if (PDFViewer == null || Selector == null || !AllowAreaSelect) { return; } AreaDrawData.HitAreaPos = Mouse.GetPosition(PDFViewer); AreaDrawData.MoveAreaPos = AreaDrawData.HitAreaPos; PDFViewer.GetPointPageInfo(AreaDrawData.HitAreaPos, out int pageIndex, out Rect paintRect, out Rect pageBound); if (pageIndex >= 0) { AreaDrawData.HitPageIndex = pageIndex; AreaDrawData.HitAreaBound = pageBound; PDFViewer.CanHorizontallyScroll = false; PDFViewer.CanVerticallyScroll = false; PDFViewer.EnableZoom(false); DrawSelect = false; } } private void AnnotSelectMoveHit() { if (!AllowMultiSelect) { return; } AreaMoveData.HitPageIndex = -1; if (PDFViewer == null || Selector == null) { return; } AreaMoveData.HitAreaPos = Mouse.GetPosition(PDFViewer); AreaMoveData.MoveAreaPos = AreaMoveData.HitAreaPos; PDFViewer.GetPointPageInfo(AreaMoveData.HitAreaPos, out int pageIndex, out Rect paintRect, out Rect pageBound); if (pageIndex >= 0) { AreaMoveData.HitPageIndex = pageIndex; AreaMoveData.HitAreaBound = pageBound; } } private void AnnotSelectAreaDraw() { if (!AllowMultiSelect) { return; } if (AreaDrawData.HitPageIndex < 0 || PDFViewer == null || Selector == null) { return; } AreaDrawData.MoveAreaPos = Mouse.GetPosition(PDFViewer); Rect moveRect = new Rect(AreaDrawData.HitAreaPos, AreaDrawData.MoveAreaPos); moveRect.Intersect(AreaDrawData.HitAreaBound); DrawingContext drawDC = Selector.RenderOpen(); drawDC.DrawRectangle(Selector.DrawBrush, Selector.DrawPen, moveRect); drawDC.Close(); } private bool AnnotSelectAreaSelect(bool onlyWidget = false, bool onlyAnnot = false) { if (!AllowMultiSelect) { return false; } if (AreaDrawData.HitPageIndex < 0 || PDFViewer == null || Selector == null) { return false; } PDFViewer.CanHorizontallyScroll = true; PDFViewer.CanVerticallyScroll = true; PDFViewer.EnableZoom(true); Selector.ClearItem(); Selector.CleanDraw(); AreaDrawData.HitPageIndex = -1; DrawSelect = true; if (PDFViewer.CurrentRenderFrame != null && PDFViewer.CurrentRenderFrame.AnnotDataList != null) { Rect areaRect = new Rect(AreaDrawData.HitAreaPos, AreaDrawData.MoveAreaPos); areaRect.Intersect(AreaDrawData.HitAreaBound); foreach (AnnotData checkItem in PDFViewer.CurrentRenderFrame.AnnotDataList) { if (onlyWidget && checkItem.AnnotType != C_ANNOTATION_TYPE.C_ANNOTATION_WIDGET) { continue; } if (onlyAnnot && checkItem.AnnotType == C_ANNOTATION_TYPE.C_ANNOTATION_WIDGET) { continue; } if (areaRect.IntersectsWith(checkItem.PaintRect)) { Selector.AddItem(checkItem); } } Selector.Draw(); } return true; } private BaseAnnot AnnotSelectGetAnnot() { if (PDFViewer != null && Selector != null && Selector.SelectAnnots != null && Selector.SelectAnnots.Count == 1) { AnnotData annotData = Selector.SelectAnnots[0]; BaseLayer checkLayer = PDFViewer.GetViewForTag(PDFViewer.GetAnnotViewTag()); if (checkLayer != null && checkLayer is AnnotLayer) { AnnotLayer annotLayer = (AnnotLayer)checkLayer; return annotLayer.GetAnnotForIndex(annotData.PageIndex, annotData.AnnotIndex); } } return null; } private int AnnotSelectGetCount() { if (Selector != null) { return Selector.GetSelectCount(); } return 0; } private void AnnotSelectAreaHover() { if (!AllowMultiSelect) { return; } if (PDFViewer == null || Selector == null || Selector.GetSelectCount() < 2) { return; } Point movePos = Mouse.GetPosition(PDFViewer); PointControlType hitPoint = Selector.GetHitControlIndex(movePos); Cursor oldCursor = this.Cursor; Cursor newCursor = this.Cursor; switch (hitPoint) { case PointControlType.LeftTop: case PointControlType.RightBottom: newCursor = Cursors.SizeNWSE; break; case PointControlType.LeftMiddle: case PointControlType.RightMiddle: newCursor = Cursors.SizeWE; break; case PointControlType.LeftBottom: case PointControlType.RightTop: newCursor = Cursors.SizeNESW; break; case PointControlType.MiddlBottom: case PointControlType.MiddleTop: newCursor = Cursors.SizeNS; break; case PointControlType.Body: newCursor = Cursors.SizeAll; break; default: newCursor = Cursors.Arrow; break; } if (oldCursor != newCursor) { PDFViewer.Cursor = newCursor; this.Cursor = newCursor; } } private bool AnnotSelectAreaHitTest() { if (!AllowMultiSelect) { return false; } if (PDFViewer == null || Selector == null || Selector.GetSelectCount() < 2) { return false; } Point movePos = Mouse.GetPosition(PDFViewer); HitTestResult hitResult = VisualTreeHelper.HitTest(PDFViewer, movePos); if (hitResult != null && hitResult.VisualHit is AnnotSelector) { return true; } return false; } private bool AnnotSelectMoveDraw() { if (!AllowMultiSelect) { return false; } if (AreaMoveData.HitPageIndex < 0 || PDFViewer == null || Selector == null || Selector.GetSelectCount() < 2) { return false; } if (Mouse.LeftButton != MouseButtonState.Pressed) { return false; } Point movePos = Mouse.GetPosition(PDFViewer); Point moveOffset = new Point(movePos.X - AreaMoveData.HitAreaPos.X, movePos.Y - AreaMoveData.HitAreaPos.Y); PointControlType hitPointType = Selector.GetHitControlIndex(AreaMoveData.HitAreaPos); switch (hitPointType) { default: case PointControlType.None: return false; case PointControlType.Body: AnnotSelectMove(); return true; case PointControlType.LeftTop: case PointControlType.LeftMiddle: case PointControlType.LeftBottom: case PointControlType.MiddlBottom: case PointControlType.RightBottom: case PointControlType.RightMiddle: case PointControlType.RightTop: case PointControlType.MiddleTop: if (CanResize(hitPointType, moveOffset, Selector.GetOutBoundRect(), AreaMoveData.HitAreaBound)) { AnnotSelectResize(hitPointType, moveOffset, Selector.GetOutBoundRect(), AreaMoveData.HitAreaBound); } return true; } } private void AnnotSelectMove() { Point movePos = Mouse.GetPosition(PDFViewer); Vector offset = movePos - AreaMoveData.HitAreaPos; Rect boundRect = Selector.GetOutBoundRect(); Point boundCenter = new Point(boundRect.Left + boundRect.Width / 2, boundRect.Top + boundRect.Height / 2); Point moveCenter = new Point(boundCenter.X + offset.X, boundCenter.Y + offset.Y); moveCenter.X = Math.Max(AreaMoveData.HitAreaBound.Left + boundRect.Width / 2, moveCenter.X); moveCenter.X = Math.Min(AreaMoveData.HitAreaBound.Right - boundRect.Width / 2, moveCenter.X); moveCenter.Y = Math.Max(AreaMoveData.HitAreaBound.Top + boundRect.Height / 2, moveCenter.Y); moveCenter.Y = Math.Min(AreaMoveData.HitAreaBound.Bottom - boundRect.Height / 2, moveCenter.Y); Rect moveRect = new Rect(moveCenter.X - boundRect.Width / 2, moveCenter.Y - boundRect.Height / 2, boundRect.Width, boundRect.Height); OffsetPos = new Point(moveCenter.X - boundCenter.X, moveCenter.Y - boundCenter.Y); DrawingContext drawDC = Selector.RenderOpen(); Selector.DrawOutBound(drawDC); Selector.DrawIndividual(drawDC); Selector.DrawControlPoint(drawDC); drawDC.DrawRectangle(Selector.DrawBrush, Selector.DrawPen, moveRect); foreach (AnnotData checkItem in Selector.SelectAnnots) { Rect childRect = new Rect(checkItem.PaintRect.X + OffsetPos.X, checkItem.PaintRect.Y + OffsetPos.Y, checkItem.PaintRect.Width, checkItem.PaintRect.Height); drawDC.DrawRectangle(Selector.DrawBrush, Selector.DrawPen, childRect); } drawDC.Close(); } private void AnnotSelectResize(PointControlType controlType, Point moveOffset, Rect maxRect, Rect boundRect) { if (maxRect == Rect.Empty || maxRect.Width == 0 || maxRect.Height == 0) { return; } double ratioX = maxRect.Width > 0 ? maxRect.Height / maxRect.Width : 1; double ratioY = maxRect.Height > 0 ? maxRect.Width / maxRect.Height : 1; Point offsetPos = moveOffset; switch (controlType) { case PointControlType.LeftTop: case PointControlType.RightBottom: offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? -1 : 1)); break; case PointControlType.LeftBottom: case PointControlType.RightTop: offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? 1 : -1)); break; case PointControlType.LeftMiddle: offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? 1 : -1)); break; case PointControlType.RightMiddle: offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? -1 : 1)); break; case PointControlType.MiddlBottom: offsetPos = new Point(Math.Abs(moveOffset.Y) * ratioY * (moveOffset.Y < 0 ? 1 : -1), moveOffset.Y); break; case PointControlType.MiddleTop: offsetPos = new Point(Math.Abs(moveOffset.Y) * ratioY * (moveOffset.Y < 0 ? -1 : 1), moveOffset.Y); break; } OffsetPos = offsetPos; double left = maxRect.Left; double top = maxRect.Top; double right = maxRect.Right; double bottom = maxRect.Bottom; switch (controlType) { case PointControlType.LeftTop://左上 left += offsetPos.X; top += offsetPos.Y; break; case PointControlType.LeftMiddle://左中 left += offsetPos.X; top -= offsetPos.Y / 2; bottom += offsetPos.Y / 2; break; case PointControlType.LeftBottom://左下 left += offsetPos.X; bottom += offsetPos.Y; break; case PointControlType.MiddlBottom://中下 bottom += offsetPos.Y; left += offsetPos.X / 2; right -= offsetPos.X / 2; break; case PointControlType.RightBottom://右下 right += offsetPos.X; bottom += offsetPos.Y; break; case PointControlType.RightMiddle://右中 right += offsetPos.X; top -= offsetPos.Y / 2; bottom += offsetPos.Y / 2; break; case PointControlType.RightTop://右上 right += offsetPos.X; top += offsetPos.Y; break; case PointControlType.MiddleTop://中上 top += offsetPos.Y; left += offsetPos.X / 2; right -= offsetPos.X / 2; break; default: break; } Rect newRect = new Rect(new Point(left, top), new Point(right, bottom)); DrawingContext drawDC = Selector.RenderOpen(); Selector.DrawOutBound(drawDC); Selector.DrawIndividual(drawDC); Selector.DrawControlPoint(drawDC); drawDC.DrawRectangle(Selector.DrawBrush, Selector.DrawPen, newRect); foreach (AnnotData checkItem in Selector.SelectAnnots) { double distanceLeft = checkItem.PaintRect.Left - maxRect.Left; double newLeft = newRect.Width * distanceLeft / maxRect.Width + newRect.Left; double distanceRight = maxRect.Right - checkItem.PaintRect.Right; double newRight = newRect.Right - newRect.Width / maxRect.Width * distanceRight; double distanceTop = checkItem.PaintRect.Top - maxRect.Top; double newTop = newRect.Height * distanceTop / maxRect.Height + newRect.Top; double distanceBottom = maxRect.Bottom - checkItem.PaintRect.Bottom; double newBottom = newRect.Bottom - newRect.Height / maxRect.Height * distanceBottom; Rect newClient = new Rect(newLeft, newTop, newRight - newLeft, newBottom - newTop); if (newClient != Rect.Empty && newClient.Width > 0 && newClient.Height > 0) { drawDC.DrawRectangle(Selector.DrawBrush, Selector.DrawPen, newClient); } } drawDC.Close(); } private bool CanResize(PointControlType controlType, Point moveOffset, Rect maxRect, Rect boundRect) { if (maxRect == Rect.Empty || maxRect.Width == 0 || maxRect.Height == 0) { return false; } double ratioX = maxRect.Width > 0 ? maxRect.Height / maxRect.Width : 1; double ratioY = maxRect.Height > 0 ? maxRect.Width / maxRect.Height : 1; Point offsetPos = moveOffset; switch (controlType) { case PointControlType.LeftTop: case PointControlType.RightBottom: offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? -1 : 1)); break; case PointControlType.LeftBottom: case PointControlType.RightTop: offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? 1 : -1)); break; case PointControlType.LeftMiddle: offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? 1 : -1)); break; case PointControlType.RightMiddle: offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? -1 : 1)); break; case PointControlType.MiddlBottom: offsetPos = new Point(Math.Abs(moveOffset.Y) * ratioY * (moveOffset.Y < 0 ? 1 : -1), moveOffset.Y); break; case PointControlType.MiddleTop: offsetPos = new Point(Math.Abs(moveOffset.Y) * ratioY * (moveOffset.Y < 0 ? -1 : 1), moveOffset.Y); break; } double left = maxRect.Left; double top = maxRect.Top; double right = maxRect.Right; double bottom = maxRect.Bottom; switch (controlType) { case PointControlType.LeftTop://左上 left += offsetPos.X; top += offsetPos.Y; break; case PointControlType.LeftMiddle://左中 left += offsetPos.X; top -= offsetPos.Y / 2; bottom += offsetPos.Y / 2; break; case PointControlType.LeftBottom://左下 left += offsetPos.X; bottom += offsetPos.Y; break; case PointControlType.MiddlBottom://中下 bottom += offsetPos.Y; left += offsetPos.X / 2; right -= offsetPos.X / 2; break; case PointControlType.RightBottom://右下 right += offsetPos.X; bottom += offsetPos.Y; break; case PointControlType.RightMiddle://右中 right += offsetPos.X; top -= offsetPos.Y / 2; bottom += offsetPos.Y / 2; break; case PointControlType.RightTop://右上 right += offsetPos.X; top += offsetPos.Y; break; case PointControlType.MiddleTop://中上 top += offsetPos.Y; left += offsetPos.X / 2; right -= offsetPos.X / 2; break; default: break; } Rect newRect = new Rect(new Point(left, top), new Point(right, bottom)); if (newRect.Left < boundRect.Left || newRect.Top < boundRect.Top || newRect.Bottom > boundRect.Bottom || newRect.Right > boundRect.Right) { return false; } return true; } private void AnnotSelectSave() { if (!AllowMultiSelect) { return; } if (AreaMoveData.HitPageIndex < 0 || PDFViewer == null || Selector == null || Selector.GetSelectCount() < 2) { return; } if (!IsMoved) { return; } PointControlType hitPointType = Selector.GetHitControlIndex(AreaMoveData.HitAreaPos); switch (hitPointType) { default: case PointControlType.None: return; case PointControlType.Body: AnnotSelectMoveSave(); PDFViewer?.UpdateRenderFrame(); return; case PointControlType.LeftTop: case PointControlType.LeftMiddle: case PointControlType.LeftBottom: case PointControlType.MiddlBottom: case PointControlType.RightBottom: case PointControlType.RightMiddle: case PointControlType.RightTop: case PointControlType.MiddleTop: AnnotSelectResizeSave(hitPointType, OffsetPos, Selector.GetOutBoundRect(), AreaMoveData.HitAreaBound); PDFViewer?.UpdateRenderFrame(); return; } } private void AnnotSelectMoveSave() { GroupHistory historyGroup = new GroupHistory(); foreach (AnnotData checkItem in Selector.SelectAnnots) { if (checkItem.Annot == null || checkItem.Annot.IsValid() == false) { continue; } Rect childRect = new Rect(checkItem.PaintRect.X + OffsetPos.X, checkItem.PaintRect.Y + OffsetPos.Y, checkItem.PaintRect.Width, checkItem.PaintRect.Height); Rect saveRect = new Rect( childRect.Left - checkItem.PaintOffset.Left + checkItem.CropLeft * checkItem.CurrentZoom, childRect.Top - checkItem.PaintOffset.Top + checkItem.CropTop * checkItem.CurrentZoom, childRect.Width, childRect.Height); Rect noZoomRect = new Rect( saveRect.Left / checkItem.CurrentZoom, saveRect.Top / checkItem.CurrentZoom, saveRect.Width / checkItem.CurrentZoom, saveRect.Height / checkItem.CurrentZoom); Rect rawRect = DpiHelper.StandardRectToPDFRect(noZoomRect); AnnotHistory historyItem = ParamConverter.CreateHistory(checkItem.Annot); AnnotParam prevParam = ParamConverter.CPDFDataConverterToAnnotParam(PDFViewer.GetDocument(), checkItem.PageIndex, checkItem.Annot); checkItem.Annot.SetRect(new CRect((float)rawRect.Left, (float)rawRect.Bottom, (float)rawRect.Right, (float)rawRect.Top)); AnnotParam currentParam = ParamConverter.CPDFDataConverterToAnnotParam(PDFViewer.GetDocument(), checkItem.PageIndex, checkItem.Annot); historyItem.PreviousParam = prevParam; historyItem.CurrentParam = currentParam; historyItem.Action = HistoryAction.Update; historyItem.PDFDoc = PDFViewer.GetDocument(); historyGroup.Histories.Add(historyItem); } if (historyGroup.Histories.Count > 0 && PDFViewer != null) { PDFViewer.UndoManager?.AddHistory(historyGroup); PDFViewer.UpdateAnnotFrame(); } } private void AnnotSelectResizeSave(PointControlType controlType, Point offsetPos, Rect maxRect, Rect boundRect) { double left = maxRect.Left; double top = maxRect.Top; double right = maxRect.Right; double bottom = maxRect.Bottom; switch (controlType) { case PointControlType.LeftTop://左上 left += offsetPos.X; top += offsetPos.Y; break; case PointControlType.LeftMiddle://左中 left += offsetPos.X; top -= offsetPos.Y / 2; bottom += offsetPos.Y / 2; break; case PointControlType.LeftBottom://左下 left += offsetPos.X; bottom += offsetPos.Y; break; case PointControlType.MiddlBottom://中下 bottom += offsetPos.Y; left += offsetPos.X / 2; right -= offsetPos.X / 2; break; case PointControlType.RightBottom://右下 right += offsetPos.X; bottom += offsetPos.Y; break; case PointControlType.RightMiddle://右中 right += offsetPos.X; top -= offsetPos.Y / 2; bottom += offsetPos.Y / 2; break; case PointControlType.RightTop://右上 right += offsetPos.X; top += offsetPos.Y; break; case PointControlType.MiddleTop://中上 top += offsetPos.Y; left += offsetPos.X / 2; right -= offsetPos.X / 2; break; default: break; } Rect newRect = new Rect(new Point(left, top), new Point(right, bottom)); GroupHistory historyGroup = new GroupHistory(); foreach (AnnotData checkItem in Selector.SelectAnnots) { if (checkItem.Annot == null || checkItem.Annot.IsValid() == false) { continue; } double distanceLeft = checkItem.PaintRect.Left - maxRect.Left; double newLeft = newRect.Width * distanceLeft / maxRect.Width + newRect.Left; double distanceRight = maxRect.Right - checkItem.PaintRect.Right; double newRight = newRect.Right - newRect.Width / maxRect.Width * distanceRight; double distanceTop = checkItem.PaintRect.Top - maxRect.Top; double newTop = newRect.Height * distanceTop / maxRect.Height + newRect.Top; double distanceBottom = maxRect.Bottom - checkItem.PaintRect.Bottom; double newBottom = newRect.Bottom - newRect.Height / maxRect.Height * distanceBottom; Rect newClient = new Rect(newLeft, newTop, newRight - newLeft, newBottom - newTop); if (newClient != Rect.Empty && newClient.Width > 0 && newClient.Height > 0) { Rect saveRect = new Rect( newClient.Left - checkItem.PaintOffset.Left + checkItem.CropLeft * checkItem.CurrentZoom, newClient.Top - checkItem.PaintOffset.Top + checkItem.CropTop * checkItem.CurrentZoom, newClient.Width, newClient.Height); Rect noZoomRect = new Rect( saveRect.Left / checkItem.CurrentZoom, saveRect.Top / checkItem.CurrentZoom, saveRect.Width / checkItem.CurrentZoom, saveRect.Height / checkItem.CurrentZoom); Rect rawRect = DpiHelper.StandardRectToPDFRect(noZoomRect); AnnotHistory historyItem = ParamConverter.CreateHistory(checkItem.Annot); AnnotParam prevParam = ParamConverter.CPDFDataConverterToAnnotParam(PDFViewer.GetDocument(), checkItem.PageIndex, checkItem.Annot); checkItem.Annot.SetRect(new CRect((float)rawRect.Left, (float)rawRect.Bottom, (float)rawRect.Right, (float)rawRect.Top)); AnnotParam currentParam = ParamConverter.CPDFDataConverterToAnnotParam(PDFViewer.GetDocument(), checkItem.PageIndex, checkItem.Annot); historyItem.PreviousParam = prevParam; historyItem.CurrentParam = currentParam; historyItem.Action = HistoryAction.Update; historyItem.PDFDoc = PDFViewer.GetDocument(); historyGroup.Histories.Add(historyItem); } } if (historyGroup.Histories.Count > 0 && PDFViewer != null) { PDFViewer.UndoManager?.AddHistory(historyGroup); PDFViewer.UpdateAnnotFrame(); } } private void AnnotSelectClean() { Selector?.CleanDraw(); Selector?.ClearItem(); } private bool AnnotSelectCommandSupport(RoutedUICommand uiCmd) { if (!AllowMultiSelect) { return false; } if (uiCmd == null || PDFViewer == null || Selector == null) { return false; } switch (uiCmd.Name) { case "Copy": case "Cut": case "Delete": return Selector.GetSelectCount() >= 2; case "Paste": return AnnotParamList.Count() >= 2; default: break; } return false; } private void AnnotSelectCommandExecute(RoutedUICommand uiCmd) { if (!AllowMultiSelect) { return; } if (uiCmd == null || string.IsNullOrEmpty(uiCmd.Name) || PDFViewer == null || Selector == null) { return; } switch (uiCmd.Name) { case "Copy": AnnotSelectCopy(); break; case "Cut": AnnotSelectCopy(); AnnotSelectDelete(); break; case "Delete": AnnotSelectDelete(); break; case "Paste": AnnotSelectPaste(); break; default: return; } } private void AnnotSelectCopy() { AnnotParamList?.Clear(); if (!AllowMultiSelect) { return; } if (Selector.GetSelectCount() < 2) { return; } foreach (AnnotData checkItem in Selector.SelectAnnots) { if (checkItem == null || checkItem.Annot == null || checkItem.Annot.IsValid() == false) { continue; } AnnotParam prevParam = ParamConverter.CPDFDataConverterToAnnotParam(PDFViewer.GetDocument(), checkItem.PageIndex, checkItem.Annot); if (prevParam == null) { continue; } AnnotParamList.Add(prevParam); } } private void AnnotSelectDelete() { if (!AllowMultiSelect) { return; } if (Selector.GetSelectCount() < 2) { return; } GroupHistory historyGroup = new GroupHistory(); Dictionary removeDict = new Dictionary(); foreach (AnnotData checkItem in Selector.SelectAnnots) { if (checkItem == null || checkItem.Annot == null || checkItem.Annot.IsValid() == false) { continue; } AnnotHistory historyItem = ParamConverter.CreateHistory(checkItem.Annot); AnnotParam prevParam = ParamConverter.CPDFDataConverterToAnnotParam(PDFViewer.GetDocument(), checkItem.PageIndex, checkItem.Annot); if (prevParam == null || historyItem == null) { continue; } historyItem.CurrentParam = prevParam; historyItem.Action = HistoryAction.Remove; historyItem.PDFDoc = PDFViewer.GetDocument(); removeDict[historyItem] = checkItem.Annot; } foreach (AnnotHistory annotKey in removeDict.Keys) { CPDFAnnotation removeAnnot = removeDict[annotKey]; if (removeAnnot.RemoveAnnot()) { historyGroup.Histories.Add(annotKey); } } if (historyGroup.Histories.Count > 0) { CleanSelectedRect(); AnnotSelectClean(); PDFViewer?.UndoManager.AddHistory(historyGroup); PDFViewer?.UpdateAnnotFrame(); PDFViewer?.UpdateRenderFrame(); } } private void AnnotSelectPaste() { if (!AllowMultiSelect) { return; } double left = 0; double right = 0; double top = 0; double bottom = 0; Point point = rightPressPoint; rightPressPoint = new Point(-1, -1); for (int i = 0; i < AnnotParamList.Count; i++) { AnnotParam checkParam = AnnotParamList[i]; if (i == 0) { left = checkParam.ClientRect.left; top = checkParam.ClientRect.top; bottom = checkParam.ClientRect.bottom; right = checkParam.ClientRect.right; continue; } left = Math.Min(left, checkParam.ClientRect.left); right = Math.Max(right, checkParam.ClientRect.right); top = Math.Min(top, checkParam.ClientRect.top); bottom = Math.Max(bottom, checkParam.ClientRect.bottom); } Point offsetPos = new Point(25, 25); PDFViewer.GetPointPageInfo(point, out int pageIndex, out Rect paintRect, out Rect pageBound); if (pageIndex >= 0) { Point zoomPoint = new Point((point.X - pageBound.X) / currentZoom, (point.Y - pageBound.Y) / currentZoom); Point rawPoint = DpiHelper.StandardPointToPDFPoint(zoomPoint); double rawWidth = DpiHelper.StandardNumToPDFNum(pageBound.Width / currentZoom); double rawHeight = DpiHelper.StandardNumToPDFNum(pageBound.Height / currentZoom); offsetPos = new Point(rawPoint.X, rawPoint.Y); if (rawPoint.X + right - left > rawWidth) { offsetPos.X = rawWidth + left - right; } if (rawPoint.Y + bottom - top > rawHeight) { offsetPos.Y = rawHeight + top - bottom; } } GroupHistory historyGroup = new GroupHistory(); foreach (AnnotParam annotParam in AnnotParamList) { AnnotParam cloneItem = CloneAnnotParam(annotParam); if (cloneItem == null) { continue; } Rect saveRect = new Rect(cloneItem.ClientRect.left, cloneItem.ClientRect.top, cloneItem.ClientRect.width(), cloneItem.ClientRect.height()); saveRect.X = saveRect.Left - left + offsetPos.X; saveRect.Y = saveRect.Top - top + offsetPos.Y; cloneItem.PageIndex = pageIndex; cloneItem.ClientRect = new CRect((float)saveRect.Left, (float)saveRect.Bottom, (float)saveRect.Right, (float)saveRect.Top); AnnotHistory historyItem = ParamConverter.CreateHistory(annotParam); historyItem.CurrentParam = cloneItem; historyItem.PDFDoc = PDFViewer.GetDocument(); historyItem.Add(); historyGroup.Histories.Add(historyItem); } if (historyGroup.Histories.Count > 0 && PDFViewer != null) { CleanSelectedRect(); AnnotSelectClean(); PDFViewer.UndoManager?.AddHistory(historyGroup); PDFViewer.UpdateAnnotFrame(); } } private AnnotParam CloneAnnotParam(AnnotParam oldParam) { if (oldParam != null) { AnnotParam newParam = new AnnotParam(); switch (oldParam.CurrentType) { case C_ANNOTATION_TYPE.C_ANNOTATION_CIRCLE: newParam = new CircleParam(); oldParam.CopyTo(newParam); break; case C_ANNOTATION_TYPE.C_ANNOTATION_FREETEXT: newParam = new FreeTextParam(); oldParam.CopyTo(newParam); break; case C_ANNOTATION_TYPE.C_ANNOTATION_HIGHLIGHT: newParam = new HighlightParam(); oldParam.CopyTo(newParam); break; case C_ANNOTATION_TYPE.C_ANNOTATION_INK: newParam = new InkParam(); oldParam.CopyTo(newParam); break; case C_ANNOTATION_TYPE.C_ANNOTATION_LINE: newParam = new LineParam(); oldParam.CopyTo(newParam); break; case C_ANNOTATION_TYPE.C_ANNOTATION_LINK: newParam = new LinkParam(); oldParam.CopyTo(newParam); break; case C_ANNOTATION_TYPE.C_ANNOTATION_CARET: newParam = new RedactParam(); oldParam.CopyTo(newParam); break; case C_ANNOTATION_TYPE.C_ANNOTATION_SQUARE: newParam = new SquareParam(); oldParam.CopyTo(newParam); break; case C_ANNOTATION_TYPE.C_ANNOTATION_SQUIGGLY: newParam = new SquareParam(); oldParam.CopyTo(newParam); break; case C_ANNOTATION_TYPE.C_ANNOTATION_STAMP: newParam = new StampParam(); oldParam.CopyTo(newParam); break; case C_ANNOTATION_TYPE.C_ANNOTATION_TEXT: newParam = new StickyNoteParam(); oldParam.CopyTo(newParam); break; case C_ANNOTATION_TYPE.C_ANNOTATION_STRIKEOUT: newParam = new StickyNoteParam(); oldParam.CopyTo(newParam); break; case C_ANNOTATION_TYPE.C_ANNOTATION_UNDERLINE: newParam = new UnderlineParam(); oldParam.CopyTo(newParam); break; case C_ANNOTATION_TYPE.C_ANNOTATION_WIDGET: WidgetParm widgetParam = oldParam as WidgetParm; if (widgetParam != null) { switch (widgetParam.WidgetType) { case C_WIDGET_TYPE.WIDGET_CHECKBOX: newParam = new CheckBoxParam(); oldParam.CopyTo(newParam); break; case C_WIDGET_TYPE.WIDGET_COMBOBOX: newParam = new ComboBoxParam(); oldParam.CopyTo(newParam); break; case C_WIDGET_TYPE.WIDGET_LISTBOX: newParam = new ListBoxParam(); oldParam.CopyTo(newParam); break; case C_WIDGET_TYPE.WIDGET_PUSHBUTTON: newParam = new PushButtonParam(); oldParam.CopyTo(newParam); break; case C_WIDGET_TYPE.WIDGET_RADIOBUTTON: newParam = new RadioButtonParam(); oldParam.CopyTo(newParam); break; case C_WIDGET_TYPE.WIDGET_SIGNATUREFIELDS: newParam = new SignatureParam(); oldParam.CopyTo(newParam); break; case C_WIDGET_TYPE.WIDGET_TEXTFIELD: newParam = new TextBoxParam(); oldParam.CopyTo(newParam); break; default: return null; } } break; default: return null; } return newParam; } return null; } } }