CPDFViewerTool.AnnotSelector.cs 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142
  1. using ComPDFKit.Import;
  2. using ComPDFKit.PDFAnnotation;
  3. using ComPDFKit.PDFAnnotation.Form;
  4. using ComPDFKit.Tool.DrawTool;
  5. using ComPDFKit.Tool.Help;
  6. using ComPDFKit.Tool.UndoManger;
  7. using ComPDFKitViewer;
  8. using ComPDFKitViewer.BaseObject;
  9. using ComPDFKitViewer.Helper;
  10. using ComPDFKitViewer.Layer;
  11. using System;
  12. using System.Collections.Generic;
  13. using System.Linq;
  14. using System.Windows;
  15. using System.Windows.Input;
  16. using System.Windows.Media;
  17. namespace ComPDFKit.Tool
  18. {
  19. public partial class CPDFViewerTool
  20. {
  21. private class AnnotSelectAreaData
  22. {
  23. public Point HitAreaPos { get; set; }
  24. public Point MoveAreaPos { get; set; }
  25. public Rect HitAreaBound { get; set; }
  26. public int HitPageIndex { get; set; } = -1;
  27. }
  28. private int AnnotSelectorIndex { get; set; } = -1;
  29. private AnnotSelector Selector { get; set; }
  30. private AnnotSelectAreaData AreaDrawData { get; set; } = new AnnotSelectAreaData();
  31. private AnnotSelectAreaData AreaMoveData { get; set; } = new AnnotSelectAreaData();
  32. private bool DrawSelect { get; set; } = true;
  33. private bool AllowMultiSelect { get; set; }
  34. private bool AllowAreaSelect { get; set; }
  35. private bool IsMoved { get; set; } = false;
  36. private Point OffsetPos { get; set; } = new Point(0, 0);
  37. private List<AnnotParam> AnnotParamList { get; set; } = new List<AnnotParam>();
  38. private void AnnotSelectInsert()
  39. {
  40. Selector = new AnnotSelector();
  41. Selector.PDFViewer = PDFViewer;
  42. int annotViewindex = PDFViewer.GetMaxViewIndex();
  43. PDFViewer.InsertView(annotViewindex, Selector);
  44. AnnotSelectorIndex = Selector.GetResTag();
  45. }
  46. private void AnnotSelectUpdate()
  47. {
  48. if (!AllowMultiSelect)
  49. {
  50. return;
  51. }
  52. if (Selector == null || Selector.SelectAnnots == null)
  53. {
  54. return;
  55. }
  56. if (PDFViewer == null || PDFViewer.CurrentRenderFrame == null)
  57. {
  58. Selector?.ClearItem();
  59. Selector?.CleanDraw();
  60. return;
  61. }
  62. List<AnnotData> annotDatas = PDFViewer.CurrentRenderFrame.AnnotDataList;
  63. if (annotDatas == null || annotDatas.Count == 0)
  64. {
  65. return;
  66. }
  67. foreach (AnnotData checkItem in Selector.SelectAnnots.ToList())
  68. {
  69. AnnotData saveItem = annotDatas.Where(x => x.PageIndex == checkItem.PageIndex && x.AnnotIndex == checkItem.AnnotIndex).FirstOrDefault();
  70. if (saveItem != null)
  71. {
  72. Selector.RemoveItem(checkItem);
  73. Selector.AddItem(saveItem);
  74. }
  75. }
  76. }
  77. public void SetAnnotAllowMultiSelect(bool isAllow)
  78. {
  79. AllowMultiSelect = isAllow;
  80. AllowAreaSelect = isAllow;
  81. }
  82. private void AnnotSelectDraw()
  83. {
  84. if (!AllowMultiSelect)
  85. {
  86. return;
  87. }
  88. if (DrawSelect == false)
  89. {
  90. return;
  91. }
  92. if (Selector?.GetSelectCount() > 1)
  93. {
  94. Selector?.Draw();
  95. return;
  96. }
  97. Selector?.CleanDraw();
  98. }
  99. private void AnnotSelectAddItem(AnnotData annotData, bool clean = true)
  100. {
  101. if (!AllowMultiSelect || annotData == null)
  102. {
  103. return;
  104. }
  105. if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
  106. {
  107. if (Selector?.HasItem(annotData) == true)
  108. {
  109. if (Selector?.GetSelectCount() != 1)
  110. {
  111. Selector?.RemoveItem(annotData);
  112. }
  113. }
  114. else
  115. {
  116. Selector?.AddItem(annotData);
  117. }
  118. return;
  119. }
  120. if (clean)
  121. {
  122. Selector?.ClearItem();
  123. Selector?.AddItem(annotData);
  124. }
  125. }
  126. private void AnnotSelectAreaHit()
  127. {
  128. if (!AllowMultiSelect)
  129. {
  130. return;
  131. }
  132. AreaDrawData.HitPageIndex = -1;
  133. if (PDFViewer == null || Selector == null || !AllowAreaSelect)
  134. {
  135. return;
  136. }
  137. AreaDrawData.HitAreaPos = Mouse.GetPosition(PDFViewer);
  138. AreaDrawData.MoveAreaPos = AreaDrawData.HitAreaPos;
  139. PDFViewer.GetPointPageInfo(AreaDrawData.HitAreaPos, out int pageIndex, out Rect paintRect, out Rect pageBound);
  140. if (pageIndex >= 0)
  141. {
  142. AreaDrawData.HitPageIndex = pageIndex;
  143. AreaDrawData.HitAreaBound = pageBound;
  144. PDFViewer.CanHorizontallyScroll = false;
  145. PDFViewer.CanVerticallyScroll = false;
  146. PDFViewer.EnableZoom(false);
  147. DrawSelect = false;
  148. }
  149. }
  150. private void AnnotSelectMoveHit()
  151. {
  152. if (!AllowMultiSelect)
  153. {
  154. return;
  155. }
  156. AreaMoveData.HitPageIndex = -1;
  157. if (PDFViewer == null || Selector == null)
  158. {
  159. return;
  160. }
  161. AreaMoveData.HitAreaPos = Mouse.GetPosition(PDFViewer);
  162. AreaMoveData.MoveAreaPos = AreaMoveData.HitAreaPos;
  163. PDFViewer.GetPointPageInfo(AreaMoveData.HitAreaPos, out int pageIndex, out Rect paintRect, out Rect pageBound);
  164. if (pageIndex >= 0)
  165. {
  166. AreaMoveData.HitPageIndex = pageIndex;
  167. AreaMoveData.HitAreaBound = pageBound;
  168. }
  169. }
  170. private void AnnotSelectAreaDraw()
  171. {
  172. if (!AllowMultiSelect)
  173. {
  174. return;
  175. }
  176. if (AreaDrawData.HitPageIndex < 0 || PDFViewer == null || Selector == null)
  177. {
  178. return;
  179. }
  180. AreaDrawData.MoveAreaPos = Mouse.GetPosition(PDFViewer);
  181. Rect moveRect = new Rect(AreaDrawData.HitAreaPos, AreaDrawData.MoveAreaPos);
  182. moveRect.Intersect(AreaDrawData.HitAreaBound);
  183. DrawingContext drawDC = Selector.RenderOpen();
  184. drawDC.DrawRectangle(Selector.DrawBrush, Selector.DrawPen, moveRect);
  185. drawDC.Close();
  186. }
  187. private bool AnnotSelectAreaSelect(bool onlyWidget = false, bool onlyAnnot = false)
  188. {
  189. if (!AllowMultiSelect)
  190. {
  191. return false;
  192. }
  193. if (AreaDrawData.HitPageIndex < 0 || PDFViewer == null || Selector == null)
  194. {
  195. return false;
  196. }
  197. PDFViewer.CanHorizontallyScroll = true;
  198. PDFViewer.CanVerticallyScroll = true;
  199. PDFViewer.EnableZoom(true);
  200. Selector.ClearItem();
  201. Selector.CleanDraw();
  202. AreaDrawData.HitPageIndex = -1;
  203. DrawSelect = true;
  204. if (PDFViewer.CurrentRenderFrame != null && PDFViewer.CurrentRenderFrame.AnnotDataList != null)
  205. {
  206. Rect areaRect = new Rect(AreaDrawData.HitAreaPos, AreaDrawData.MoveAreaPos);
  207. areaRect.Intersect(AreaDrawData.HitAreaBound);
  208. foreach (AnnotData checkItem in PDFViewer.CurrentRenderFrame.AnnotDataList)
  209. {
  210. if (onlyWidget && checkItem.AnnotType != C_ANNOTATION_TYPE.C_ANNOTATION_WIDGET)
  211. {
  212. continue;
  213. }
  214. if (onlyAnnot && checkItem.AnnotType == C_ANNOTATION_TYPE.C_ANNOTATION_WIDGET)
  215. {
  216. continue;
  217. }
  218. if (areaRect.IntersectsWith(checkItem.PaintRect))
  219. {
  220. Selector.AddItem(checkItem);
  221. }
  222. }
  223. Selector.Draw();
  224. }
  225. return true;
  226. }
  227. private BaseAnnot AnnotSelectGetAnnot()
  228. {
  229. if (PDFViewer != null && Selector != null && Selector.SelectAnnots != null && Selector.SelectAnnots.Count == 1)
  230. {
  231. AnnotData annotData = Selector.SelectAnnots[0];
  232. BaseLayer checkLayer = PDFViewer.GetViewForTag(PDFViewer.GetAnnotViewTag());
  233. if (checkLayer != null && checkLayer is AnnotLayer)
  234. {
  235. AnnotLayer annotLayer = (AnnotLayer)checkLayer;
  236. return annotLayer.GetAnnotForIndex(annotData.PageIndex, annotData.AnnotIndex);
  237. }
  238. }
  239. return null;
  240. }
  241. private int AnnotSelectGetCount()
  242. {
  243. if (Selector != null)
  244. {
  245. return Selector.GetSelectCount();
  246. }
  247. return 0;
  248. }
  249. private void AnnotSelectAreaHover()
  250. {
  251. if (!AllowMultiSelect)
  252. {
  253. return;
  254. }
  255. if (PDFViewer == null || Selector == null || Selector.GetSelectCount() < 2)
  256. {
  257. return;
  258. }
  259. Point movePos = Mouse.GetPosition(PDFViewer);
  260. PointControlType hitPoint = Selector.GetHitControlIndex(movePos);
  261. Cursor oldCursor = this.Cursor;
  262. Cursor newCursor = this.Cursor;
  263. switch (hitPoint)
  264. {
  265. case PointControlType.LeftTop:
  266. case PointControlType.RightBottom:
  267. newCursor = Cursors.SizeNWSE;
  268. break;
  269. case PointControlType.LeftMiddle:
  270. case PointControlType.RightMiddle:
  271. newCursor = Cursors.SizeWE;
  272. break;
  273. case PointControlType.LeftBottom:
  274. case PointControlType.RightTop:
  275. newCursor = Cursors.SizeNESW;
  276. break;
  277. case PointControlType.MiddlBottom:
  278. case PointControlType.MiddleTop:
  279. newCursor = Cursors.SizeNS;
  280. break;
  281. case PointControlType.Body:
  282. newCursor = Cursors.SizeAll;
  283. break;
  284. default:
  285. newCursor = Cursors.Arrow;
  286. break;
  287. }
  288. if (oldCursor != newCursor)
  289. {
  290. PDFViewer.Cursor = newCursor;
  291. this.Cursor = newCursor;
  292. }
  293. }
  294. private bool AnnotSelectAreaHitTest()
  295. {
  296. if (!AllowMultiSelect)
  297. {
  298. return false;
  299. }
  300. if (PDFViewer == null || Selector == null || Selector.GetSelectCount() < 2)
  301. {
  302. return false;
  303. }
  304. Point movePos = Mouse.GetPosition(PDFViewer);
  305. HitTestResult hitResult = VisualTreeHelper.HitTest(PDFViewer, movePos);
  306. if (hitResult != null && hitResult.VisualHit is AnnotSelector)
  307. {
  308. return true;
  309. }
  310. return false;
  311. }
  312. private bool AnnotSelectMoveDraw()
  313. {
  314. if (!AllowMultiSelect)
  315. {
  316. return false;
  317. }
  318. if (AreaMoveData.HitPageIndex < 0 || PDFViewer == null || Selector == null || Selector.GetSelectCount() < 2)
  319. {
  320. return false;
  321. }
  322. if (Mouse.LeftButton != MouseButtonState.Pressed)
  323. {
  324. return false;
  325. }
  326. Point movePos = Mouse.GetPosition(PDFViewer);
  327. Point moveOffset = new Point(movePos.X - AreaMoveData.HitAreaPos.X, movePos.Y - AreaMoveData.HitAreaPos.Y);
  328. PointControlType hitPointType = Selector.GetHitControlIndex(AreaMoveData.HitAreaPos);
  329. switch (hitPointType)
  330. {
  331. default:
  332. case PointControlType.None:
  333. return false;
  334. case PointControlType.Body:
  335. AnnotSelectMove();
  336. return true;
  337. case PointControlType.LeftTop:
  338. case PointControlType.LeftMiddle:
  339. case PointControlType.LeftBottom:
  340. case PointControlType.MiddlBottom:
  341. case PointControlType.RightBottom:
  342. case PointControlType.RightMiddle:
  343. case PointControlType.RightTop:
  344. case PointControlType.MiddleTop:
  345. if (CanResize(hitPointType, moveOffset, Selector.GetOutBoundRect(), AreaMoveData.HitAreaBound))
  346. {
  347. AnnotSelectResize(hitPointType, moveOffset, Selector.GetOutBoundRect(), AreaMoveData.HitAreaBound);
  348. }
  349. return true;
  350. }
  351. }
  352. private void AnnotSelectMove()
  353. {
  354. Point movePos = Mouse.GetPosition(PDFViewer);
  355. Vector offset = movePos - AreaMoveData.HitAreaPos;
  356. Rect boundRect = Selector.GetOutBoundRect();
  357. Point boundCenter = new Point(boundRect.Left + boundRect.Width / 2, boundRect.Top + boundRect.Height / 2);
  358. Point moveCenter = new Point(boundCenter.X + offset.X, boundCenter.Y + offset.Y);
  359. moveCenter.X = Math.Max(AreaMoveData.HitAreaBound.Left + boundRect.Width / 2, moveCenter.X);
  360. moveCenter.X = Math.Min(AreaMoveData.HitAreaBound.Right - boundRect.Width / 2, moveCenter.X);
  361. moveCenter.Y = Math.Max(AreaMoveData.HitAreaBound.Top + boundRect.Height / 2, moveCenter.Y);
  362. moveCenter.Y = Math.Min(AreaMoveData.HitAreaBound.Bottom - boundRect.Height / 2, moveCenter.Y);
  363. Rect moveRect = new Rect(moveCenter.X - boundRect.Width / 2, moveCenter.Y - boundRect.Height / 2, boundRect.Width, boundRect.Height);
  364. OffsetPos = new Point(moveCenter.X - boundCenter.X, moveCenter.Y - boundCenter.Y);
  365. DrawingContext drawDC = Selector.RenderOpen();
  366. Selector.DrawOutBound(drawDC);
  367. Selector.DrawIndividual(drawDC);
  368. Selector.DrawControlPoint(drawDC);
  369. drawDC.DrawRectangle(Selector.DrawBrush, Selector.DrawPen, moveRect);
  370. foreach (AnnotData checkItem in Selector.SelectAnnots)
  371. {
  372. Rect childRect = new Rect(checkItem.PaintRect.X + OffsetPos.X, checkItem.PaintRect.Y + OffsetPos.Y, checkItem.PaintRect.Width, checkItem.PaintRect.Height);
  373. drawDC.DrawRectangle(Selector.DrawBrush, Selector.DrawPen, childRect);
  374. }
  375. drawDC.Close();
  376. }
  377. private void AnnotSelectResize(PointControlType controlType, Point moveOffset, Rect maxRect, Rect boundRect)
  378. {
  379. if (maxRect == Rect.Empty || maxRect.Width == 0 || maxRect.Height == 0)
  380. {
  381. return;
  382. }
  383. double ratioX = maxRect.Width > 0 ? maxRect.Height / maxRect.Width : 1;
  384. double ratioY = maxRect.Height > 0 ? maxRect.Width / maxRect.Height : 1;
  385. Point offsetPos = moveOffset;
  386. switch (controlType)
  387. {
  388. case PointControlType.LeftTop:
  389. case PointControlType.RightBottom:
  390. offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? -1 : 1));
  391. break;
  392. case PointControlType.LeftBottom:
  393. case PointControlType.RightTop:
  394. offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? 1 : -1));
  395. break;
  396. case PointControlType.LeftMiddle:
  397. offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? 1 : -1));
  398. break;
  399. case PointControlType.RightMiddle:
  400. offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? -1 : 1));
  401. break;
  402. case PointControlType.MiddlBottom:
  403. offsetPos = new Point(Math.Abs(moveOffset.Y) * ratioY * (moveOffset.Y < 0 ? 1 : -1), moveOffset.Y);
  404. break;
  405. case PointControlType.MiddleTop:
  406. offsetPos = new Point(Math.Abs(moveOffset.Y) * ratioY * (moveOffset.Y < 0 ? -1 : 1), moveOffset.Y);
  407. break;
  408. }
  409. OffsetPos = offsetPos;
  410. double left = maxRect.Left;
  411. double top = maxRect.Top;
  412. double right = maxRect.Right;
  413. double bottom = maxRect.Bottom;
  414. switch (controlType)
  415. {
  416. case PointControlType.LeftTop://左上
  417. left += offsetPos.X;
  418. top += offsetPos.Y;
  419. break;
  420. case PointControlType.LeftMiddle://左中
  421. left += offsetPos.X;
  422. top -= offsetPos.Y / 2;
  423. bottom += offsetPos.Y / 2;
  424. break;
  425. case PointControlType.LeftBottom://左下
  426. left += offsetPos.X;
  427. bottom += offsetPos.Y;
  428. break;
  429. case PointControlType.MiddlBottom://中下
  430. bottom += offsetPos.Y;
  431. left += offsetPos.X / 2;
  432. right -= offsetPos.X / 2;
  433. break;
  434. case PointControlType.RightBottom://右下
  435. right += offsetPos.X;
  436. bottom += offsetPos.Y;
  437. break;
  438. case PointControlType.RightMiddle://右中
  439. right += offsetPos.X;
  440. top -= offsetPos.Y / 2;
  441. bottom += offsetPos.Y / 2;
  442. break;
  443. case PointControlType.RightTop://右上
  444. right += offsetPos.X;
  445. top += offsetPos.Y;
  446. break;
  447. case PointControlType.MiddleTop://中上
  448. top += offsetPos.Y;
  449. left += offsetPos.X / 2;
  450. right -= offsetPos.X / 2;
  451. break;
  452. default:
  453. break;
  454. }
  455. Rect newRect = new Rect(new Point(left, top), new Point(right, bottom));
  456. DrawingContext drawDC = Selector.RenderOpen();
  457. Selector.DrawOutBound(drawDC);
  458. Selector.DrawIndividual(drawDC);
  459. Selector.DrawControlPoint(drawDC);
  460. drawDC.DrawRectangle(Selector.DrawBrush, Selector.DrawPen, newRect);
  461. foreach (AnnotData checkItem in Selector.SelectAnnots)
  462. {
  463. double distanceLeft = checkItem.PaintRect.Left - maxRect.Left;
  464. double newLeft = newRect.Width * distanceLeft / maxRect.Width + newRect.Left;
  465. double distanceRight = maxRect.Right - checkItem.PaintRect.Right;
  466. double newRight = newRect.Right - newRect.Width / maxRect.Width * distanceRight;
  467. double distanceTop = checkItem.PaintRect.Top - maxRect.Top;
  468. double newTop = newRect.Height * distanceTop / maxRect.Height + newRect.Top;
  469. double distanceBottom = maxRect.Bottom - checkItem.PaintRect.Bottom;
  470. double newBottom = newRect.Bottom - newRect.Height / maxRect.Height * distanceBottom;
  471. Rect newClient = new Rect(newLeft, newTop, newRight - newLeft, newBottom - newTop);
  472. if (newClient != Rect.Empty && newClient.Width > 0 && newClient.Height > 0)
  473. {
  474. drawDC.DrawRectangle(Selector.DrawBrush, Selector.DrawPen, newClient);
  475. }
  476. }
  477. drawDC.Close();
  478. }
  479. private bool CanResize(PointControlType controlType, Point moveOffset, Rect maxRect, Rect boundRect)
  480. {
  481. if (maxRect == Rect.Empty || maxRect.Width == 0 || maxRect.Height == 0)
  482. {
  483. return false;
  484. }
  485. double ratioX = maxRect.Width > 0 ? maxRect.Height / maxRect.Width : 1;
  486. double ratioY = maxRect.Height > 0 ? maxRect.Width / maxRect.Height : 1;
  487. Point offsetPos = moveOffset;
  488. switch (controlType)
  489. {
  490. case PointControlType.LeftTop:
  491. case PointControlType.RightBottom:
  492. offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? -1 : 1));
  493. break;
  494. case PointControlType.LeftBottom:
  495. case PointControlType.RightTop:
  496. offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? 1 : -1));
  497. break;
  498. case PointControlType.LeftMiddle:
  499. offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? 1 : -1));
  500. break;
  501. case PointControlType.RightMiddle:
  502. offsetPos = new Point(moveOffset.X, Math.Abs(moveOffset.X) * ratioX * (moveOffset.X < 0 ? -1 : 1));
  503. break;
  504. case PointControlType.MiddlBottom:
  505. offsetPos = new Point(Math.Abs(moveOffset.Y) * ratioY * (moveOffset.Y < 0 ? 1 : -1), moveOffset.Y);
  506. break;
  507. case PointControlType.MiddleTop:
  508. offsetPos = new Point(Math.Abs(moveOffset.Y) * ratioY * (moveOffset.Y < 0 ? -1 : 1), moveOffset.Y);
  509. break;
  510. }
  511. double left = maxRect.Left;
  512. double top = maxRect.Top;
  513. double right = maxRect.Right;
  514. double bottom = maxRect.Bottom;
  515. switch (controlType)
  516. {
  517. case PointControlType.LeftTop://左上
  518. left += offsetPos.X;
  519. top += offsetPos.Y;
  520. break;
  521. case PointControlType.LeftMiddle://左中
  522. left += offsetPos.X;
  523. top -= offsetPos.Y / 2;
  524. bottom += offsetPos.Y / 2;
  525. break;
  526. case PointControlType.LeftBottom://左下
  527. left += offsetPos.X;
  528. bottom += offsetPos.Y;
  529. break;
  530. case PointControlType.MiddlBottom://中下
  531. bottom += offsetPos.Y;
  532. left += offsetPos.X / 2;
  533. right -= offsetPos.X / 2;
  534. break;
  535. case PointControlType.RightBottom://右下
  536. right += offsetPos.X;
  537. bottom += offsetPos.Y;
  538. break;
  539. case PointControlType.RightMiddle://右中
  540. right += offsetPos.X;
  541. top -= offsetPos.Y / 2;
  542. bottom += offsetPos.Y / 2;
  543. break;
  544. case PointControlType.RightTop://右上
  545. right += offsetPos.X;
  546. top += offsetPos.Y;
  547. break;
  548. case PointControlType.MiddleTop://中上
  549. top += offsetPos.Y;
  550. left += offsetPos.X / 2;
  551. right -= offsetPos.X / 2;
  552. break;
  553. default:
  554. break;
  555. }
  556. Rect newRect = new Rect(new Point(left, top), new Point(right, bottom));
  557. if (newRect.Left < boundRect.Left || newRect.Top < boundRect.Top || newRect.Bottom > boundRect.Bottom || newRect.Right > boundRect.Right)
  558. {
  559. return false;
  560. }
  561. return true;
  562. }
  563. private void AnnotSelectSave()
  564. {
  565. if (!AllowMultiSelect)
  566. {
  567. return;
  568. }
  569. if (AreaMoveData.HitPageIndex < 0 || PDFViewer == null || Selector == null || Selector.GetSelectCount() < 2)
  570. {
  571. return;
  572. }
  573. if (!IsMoved)
  574. {
  575. return;
  576. }
  577. PointControlType hitPointType = Selector.GetHitControlIndex(AreaMoveData.HitAreaPos);
  578. switch (hitPointType)
  579. {
  580. default:
  581. case PointControlType.None:
  582. return;
  583. case PointControlType.Body:
  584. AnnotSelectMoveSave();
  585. PDFViewer?.UpdateRenderFrame();
  586. return;
  587. case PointControlType.LeftTop:
  588. case PointControlType.LeftMiddle:
  589. case PointControlType.LeftBottom:
  590. case PointControlType.MiddlBottom:
  591. case PointControlType.RightBottom:
  592. case PointControlType.RightMiddle:
  593. case PointControlType.RightTop:
  594. case PointControlType.MiddleTop:
  595. AnnotSelectResizeSave(hitPointType, OffsetPos, Selector.GetOutBoundRect(), AreaMoveData.HitAreaBound);
  596. PDFViewer?.UpdateRenderFrame();
  597. return;
  598. }
  599. }
  600. private void AnnotSelectMoveSave()
  601. {
  602. GroupHistory historyGroup = new GroupHistory();
  603. foreach (AnnotData checkItem in Selector.SelectAnnots)
  604. {
  605. if (checkItem.Annot == null || checkItem.Annot.IsValid() == false)
  606. {
  607. continue;
  608. }
  609. Rect childRect = new Rect(checkItem.PaintRect.X + OffsetPos.X, checkItem.PaintRect.Y + OffsetPos.Y, checkItem.PaintRect.Width, checkItem.PaintRect.Height);
  610. Rect saveRect = new Rect(
  611. childRect.Left - checkItem.PaintOffset.Left + checkItem.CropLeft * checkItem.CurrentZoom,
  612. childRect.Top - checkItem.PaintOffset.Top + checkItem.CropTop * checkItem.CurrentZoom,
  613. childRect.Width,
  614. childRect.Height);
  615. Rect noZoomRect = new Rect(
  616. saveRect.Left / checkItem.CurrentZoom,
  617. saveRect.Top / checkItem.CurrentZoom,
  618. saveRect.Width / checkItem.CurrentZoom,
  619. saveRect.Height / checkItem.CurrentZoom);
  620. Rect rawRect = DpiHelper.StandardRectToPDFRect(noZoomRect);
  621. AnnotHistory historyItem = ParamConverter.CreateHistory(checkItem.Annot);
  622. AnnotParam prevParam = ParamConverter.CPDFDataConverterToAnnotParam(PDFViewer.GetDocument(), checkItem.PageIndex, checkItem.Annot);
  623. checkItem.Annot.SetRect(new CRect((float)rawRect.Left, (float)rawRect.Bottom, (float)rawRect.Right, (float)rawRect.Top));
  624. AnnotParam currentParam = ParamConverter.CPDFDataConverterToAnnotParam(PDFViewer.GetDocument(), checkItem.PageIndex, checkItem.Annot);
  625. historyItem.PreviousParam = prevParam;
  626. historyItem.CurrentParam = currentParam;
  627. historyItem.Action = HistoryAction.Update;
  628. historyItem.PDFDoc = PDFViewer.GetDocument();
  629. historyGroup.Histories.Add(historyItem);
  630. }
  631. if (historyGroup.Histories.Count > 0 && PDFViewer != null)
  632. {
  633. PDFViewer.UndoManager?.AddHistory(historyGroup);
  634. PDFViewer.UpdateAnnotFrame();
  635. }
  636. }
  637. private void AnnotSelectResizeSave(PointControlType controlType, Point offsetPos, Rect maxRect, Rect boundRect)
  638. {
  639. double left = maxRect.Left;
  640. double top = maxRect.Top;
  641. double right = maxRect.Right;
  642. double bottom = maxRect.Bottom;
  643. switch (controlType)
  644. {
  645. case PointControlType.LeftTop://左上
  646. left += offsetPos.X;
  647. top += offsetPos.Y;
  648. break;
  649. case PointControlType.LeftMiddle://左中
  650. left += offsetPos.X;
  651. top -= offsetPos.Y / 2;
  652. bottom += offsetPos.Y / 2;
  653. break;
  654. case PointControlType.LeftBottom://左下
  655. left += offsetPos.X;
  656. bottom += offsetPos.Y;
  657. break;
  658. case PointControlType.MiddlBottom://中下
  659. bottom += offsetPos.Y;
  660. left += offsetPos.X / 2;
  661. right -= offsetPos.X / 2;
  662. break;
  663. case PointControlType.RightBottom://右下
  664. right += offsetPos.X;
  665. bottom += offsetPos.Y;
  666. break;
  667. case PointControlType.RightMiddle://右中
  668. right += offsetPos.X;
  669. top -= offsetPos.Y / 2;
  670. bottom += offsetPos.Y / 2;
  671. break;
  672. case PointControlType.RightTop://右上
  673. right += offsetPos.X;
  674. top += offsetPos.Y;
  675. break;
  676. case PointControlType.MiddleTop://中上
  677. top += offsetPos.Y;
  678. left += offsetPos.X / 2;
  679. right -= offsetPos.X / 2;
  680. break;
  681. default:
  682. break;
  683. }
  684. Rect newRect = new Rect(new Point(left, top), new Point(right, bottom));
  685. GroupHistory historyGroup = new GroupHistory();
  686. foreach (AnnotData checkItem in Selector.SelectAnnots)
  687. {
  688. if (checkItem.Annot == null || checkItem.Annot.IsValid() == false)
  689. {
  690. continue;
  691. }
  692. double distanceLeft = checkItem.PaintRect.Left - maxRect.Left;
  693. double newLeft = newRect.Width * distanceLeft / maxRect.Width + newRect.Left;
  694. double distanceRight = maxRect.Right - checkItem.PaintRect.Right;
  695. double newRight = newRect.Right - newRect.Width / maxRect.Width * distanceRight;
  696. double distanceTop = checkItem.PaintRect.Top - maxRect.Top;
  697. double newTop = newRect.Height * distanceTop / maxRect.Height + newRect.Top;
  698. double distanceBottom = maxRect.Bottom - checkItem.PaintRect.Bottom;
  699. double newBottom = newRect.Bottom - newRect.Height / maxRect.Height * distanceBottom;
  700. Rect newClient = new Rect(newLeft, newTop, newRight - newLeft, newBottom - newTop);
  701. if (newClient != Rect.Empty && newClient.Width > 0 && newClient.Height > 0)
  702. {
  703. Rect saveRect = new Rect(
  704. newClient.Left - checkItem.PaintOffset.Left + checkItem.CropLeft * checkItem.CurrentZoom,
  705. newClient.Top - checkItem.PaintOffset.Top + checkItem.CropTop * checkItem.CurrentZoom,
  706. newClient.Width,
  707. newClient.Height);
  708. Rect noZoomRect = new Rect(
  709. saveRect.Left / checkItem.CurrentZoom,
  710. saveRect.Top / checkItem.CurrentZoom,
  711. saveRect.Width / checkItem.CurrentZoom,
  712. saveRect.Height / checkItem.CurrentZoom);
  713. Rect rawRect = DpiHelper.StandardRectToPDFRect(noZoomRect);
  714. AnnotHistory historyItem = ParamConverter.CreateHistory(checkItem.Annot);
  715. AnnotParam prevParam = ParamConverter.CPDFDataConverterToAnnotParam(PDFViewer.GetDocument(), checkItem.PageIndex, checkItem.Annot);
  716. checkItem.Annot.SetRect(new CRect((float)rawRect.Left, (float)rawRect.Bottom, (float)rawRect.Right, (float)rawRect.Top));
  717. AnnotParam currentParam = ParamConverter.CPDFDataConverterToAnnotParam(PDFViewer.GetDocument(), checkItem.PageIndex, checkItem.Annot);
  718. historyItem.PreviousParam = prevParam;
  719. historyItem.CurrentParam = currentParam;
  720. historyItem.Action = HistoryAction.Update;
  721. historyItem.PDFDoc = PDFViewer.GetDocument();
  722. historyGroup.Histories.Add(historyItem);
  723. }
  724. }
  725. if (historyGroup.Histories.Count > 0 && PDFViewer != null)
  726. {
  727. PDFViewer.UndoManager?.AddHistory(historyGroup);
  728. PDFViewer.UpdateAnnotFrame();
  729. }
  730. }
  731. private void AnnotSelectClean()
  732. {
  733. Selector?.CleanDraw();
  734. Selector?.ClearItem();
  735. }
  736. private bool AnnotSelectCommandSupport(RoutedUICommand uiCmd)
  737. {
  738. if (!AllowMultiSelect)
  739. {
  740. return false;
  741. }
  742. if (uiCmd == null || PDFViewer == null || Selector == null)
  743. {
  744. return false;
  745. }
  746. switch (uiCmd.Name)
  747. {
  748. case "Copy":
  749. case "Cut":
  750. case "Delete":
  751. return Selector.GetSelectCount() >= 2;
  752. case "Paste":
  753. return AnnotParamList.Count() >= 2;
  754. default:
  755. break;
  756. }
  757. return false;
  758. }
  759. private void AnnotSelectCommandExecute(RoutedUICommand uiCmd)
  760. {
  761. if (!AllowMultiSelect)
  762. {
  763. return;
  764. }
  765. if (uiCmd == null || string.IsNullOrEmpty(uiCmd.Name) || PDFViewer == null || Selector == null)
  766. {
  767. return;
  768. }
  769. switch (uiCmd.Name)
  770. {
  771. case "Copy":
  772. AnnotSelectCopy();
  773. break;
  774. case "Cut":
  775. AnnotSelectCopy();
  776. AnnotSelectDelete();
  777. break;
  778. case "Delete":
  779. AnnotSelectDelete();
  780. break;
  781. case "Paste":
  782. AnnotSelectPaste();
  783. break;
  784. default:
  785. return;
  786. }
  787. }
  788. private void AnnotSelectCopy()
  789. {
  790. AnnotParamList?.Clear();
  791. if (!AllowMultiSelect)
  792. {
  793. return;
  794. }
  795. if (Selector.GetSelectCount() < 2)
  796. {
  797. return;
  798. }
  799. foreach (AnnotData checkItem in Selector.SelectAnnots)
  800. {
  801. if (checkItem == null || checkItem.Annot == null || checkItem.Annot.IsValid() == false)
  802. {
  803. continue;
  804. }
  805. AnnotParam prevParam = ParamConverter.CPDFDataConverterToAnnotParam(PDFViewer.GetDocument(), checkItem.PageIndex, checkItem.Annot);
  806. if (prevParam == null)
  807. {
  808. continue;
  809. }
  810. AnnotParamList.Add(prevParam);
  811. }
  812. }
  813. private void AnnotSelectDelete()
  814. {
  815. if (!AllowMultiSelect)
  816. {
  817. return;
  818. }
  819. if (Selector.GetSelectCount() < 2)
  820. {
  821. return;
  822. }
  823. GroupHistory historyGroup = new GroupHistory();
  824. Dictionary<AnnotHistory, CPDFAnnotation> removeDict = new Dictionary<AnnotHistory, CPDFAnnotation>();
  825. foreach (AnnotData checkItem in Selector.SelectAnnots)
  826. {
  827. if (checkItem == null || checkItem.Annot == null || checkItem.Annot.IsValid() == false)
  828. {
  829. continue;
  830. }
  831. AnnotHistory historyItem = ParamConverter.CreateHistory(checkItem.Annot);
  832. AnnotParam prevParam = ParamConverter.CPDFDataConverterToAnnotParam(PDFViewer.GetDocument(), checkItem.PageIndex, checkItem.Annot);
  833. if (prevParam == null || historyItem == null)
  834. {
  835. continue;
  836. }
  837. historyItem.CurrentParam = prevParam;
  838. historyItem.Action = HistoryAction.Remove;
  839. historyItem.PDFDoc = PDFViewer.GetDocument();
  840. removeDict[historyItem] = checkItem.Annot;
  841. }
  842. foreach (AnnotHistory annotKey in removeDict.Keys)
  843. {
  844. CPDFAnnotation removeAnnot = removeDict[annotKey];
  845. if (removeAnnot.RemoveAnnot())
  846. {
  847. historyGroup.Histories.Add(annotKey);
  848. }
  849. }
  850. if (historyGroup.Histories.Count > 0)
  851. {
  852. CleanSelectedRect();
  853. AnnotSelectClean();
  854. PDFViewer?.UndoManager.AddHistory(historyGroup);
  855. PDFViewer?.UpdateAnnotFrame();
  856. PDFViewer?.UpdateRenderFrame();
  857. }
  858. }
  859. private void AnnotSelectPaste()
  860. {
  861. if (!AllowMultiSelect)
  862. {
  863. return;
  864. }
  865. double left = 0;
  866. double right = 0;
  867. double top = 0;
  868. double bottom = 0;
  869. Point point = rightPressPoint;
  870. rightPressPoint = new Point(-1, -1);
  871. for (int i = 0; i < AnnotParamList.Count; i++)
  872. {
  873. AnnotParam checkParam = AnnotParamList[i];
  874. if (i == 0)
  875. {
  876. left = checkParam.ClientRect.left;
  877. top = checkParam.ClientRect.top;
  878. bottom = checkParam.ClientRect.bottom;
  879. right = checkParam.ClientRect.right;
  880. continue;
  881. }
  882. left = Math.Min(left, checkParam.ClientRect.left);
  883. right = Math.Max(right, checkParam.ClientRect.right);
  884. top = Math.Min(top, checkParam.ClientRect.top);
  885. bottom = Math.Max(bottom, checkParam.ClientRect.bottom);
  886. }
  887. Point offsetPos = new Point(25, 25);
  888. PDFViewer.GetPointPageInfo(point, out int pageIndex, out Rect paintRect, out Rect pageBound);
  889. if (pageIndex >= 0)
  890. {
  891. Point zoomPoint = new Point((point.X - pageBound.X) / currentZoom, (point.Y - pageBound.Y) / currentZoom);
  892. Point rawPoint = DpiHelper.StandardPointToPDFPoint(zoomPoint);
  893. double rawWidth = DpiHelper.StandardNumToPDFNum(pageBound.Width / currentZoom);
  894. double rawHeight = DpiHelper.StandardNumToPDFNum(pageBound.Height / currentZoom);
  895. offsetPos = new Point(rawPoint.X, rawPoint.Y);
  896. if (rawPoint.X + right - left > rawWidth)
  897. {
  898. offsetPos.X = rawWidth + left - right;
  899. }
  900. if (rawPoint.Y + bottom - top > rawHeight)
  901. {
  902. offsetPos.Y = rawHeight + top - bottom;
  903. }
  904. }
  905. GroupHistory historyGroup = new GroupHistory();
  906. foreach (AnnotParam annotParam in AnnotParamList)
  907. {
  908. AnnotParam cloneItem = CloneAnnotParam(annotParam);
  909. if (cloneItem == null)
  910. {
  911. continue;
  912. }
  913. Rect saveRect = new Rect(cloneItem.ClientRect.left, cloneItem.ClientRect.top, cloneItem.ClientRect.width(), cloneItem.ClientRect.height());
  914. saveRect.X = saveRect.Left - left + offsetPos.X;
  915. saveRect.Y = saveRect.Top - top + offsetPos.Y;
  916. cloneItem.PageIndex = pageIndex;
  917. cloneItem.ClientRect = new CRect((float)saveRect.Left, (float)saveRect.Bottom, (float)saveRect.Right, (float)saveRect.Top);
  918. AnnotHistory historyItem = ParamConverter.CreateHistory(annotParam);
  919. historyItem.CurrentParam = cloneItem;
  920. historyItem.PDFDoc = PDFViewer.GetDocument();
  921. historyItem.Add();
  922. historyGroup.Histories.Add(historyItem);
  923. }
  924. if (historyGroup.Histories.Count > 0 && PDFViewer != null)
  925. {
  926. CleanSelectedRect();
  927. AnnotSelectClean();
  928. PDFViewer.UndoManager?.AddHistory(historyGroup);
  929. PDFViewer.UpdateAnnotFrame();
  930. }
  931. }
  932. private AnnotParam CloneAnnotParam(AnnotParam oldParam)
  933. {
  934. if (oldParam != null)
  935. {
  936. AnnotParam newParam = new AnnotParam();
  937. switch (oldParam.CurrentType)
  938. {
  939. case C_ANNOTATION_TYPE.C_ANNOTATION_CIRCLE:
  940. newParam = new CircleParam();
  941. oldParam.CopyTo(newParam);
  942. break;
  943. case C_ANNOTATION_TYPE.C_ANNOTATION_FREETEXT:
  944. newParam = new FreeTextParam();
  945. oldParam.CopyTo(newParam);
  946. break;
  947. case C_ANNOTATION_TYPE.C_ANNOTATION_HIGHLIGHT:
  948. newParam = new HighlightParam();
  949. oldParam.CopyTo(newParam);
  950. break;
  951. case C_ANNOTATION_TYPE.C_ANNOTATION_INK:
  952. newParam = new InkParam();
  953. oldParam.CopyTo(newParam);
  954. break;
  955. case C_ANNOTATION_TYPE.C_ANNOTATION_LINE:
  956. newParam = new LineParam();
  957. oldParam.CopyTo(newParam);
  958. break;
  959. case C_ANNOTATION_TYPE.C_ANNOTATION_LINK:
  960. newParam = new LinkParam();
  961. oldParam.CopyTo(newParam);
  962. break;
  963. case C_ANNOTATION_TYPE.C_ANNOTATION_CARET:
  964. newParam = new RedactParam();
  965. oldParam.CopyTo(newParam);
  966. break;
  967. case C_ANNOTATION_TYPE.C_ANNOTATION_SQUARE:
  968. newParam = new SquareParam();
  969. oldParam.CopyTo(newParam);
  970. break;
  971. case C_ANNOTATION_TYPE.C_ANNOTATION_SQUIGGLY:
  972. newParam = new SquareParam();
  973. oldParam.CopyTo(newParam);
  974. break;
  975. case C_ANNOTATION_TYPE.C_ANNOTATION_STAMP:
  976. newParam = new StampParam();
  977. oldParam.CopyTo(newParam);
  978. break;
  979. case C_ANNOTATION_TYPE.C_ANNOTATION_TEXT:
  980. newParam = new StickyNoteParam();
  981. oldParam.CopyTo(newParam);
  982. break;
  983. case C_ANNOTATION_TYPE.C_ANNOTATION_STRIKEOUT:
  984. newParam = new StickyNoteParam();
  985. oldParam.CopyTo(newParam);
  986. break;
  987. case C_ANNOTATION_TYPE.C_ANNOTATION_UNDERLINE:
  988. newParam = new UnderlineParam();
  989. oldParam.CopyTo(newParam);
  990. break;
  991. case C_ANNOTATION_TYPE.C_ANNOTATION_WIDGET:
  992. WidgetParm widgetParam = oldParam as WidgetParm;
  993. if (widgetParam != null)
  994. {
  995. switch (widgetParam.WidgetType)
  996. {
  997. case C_WIDGET_TYPE.WIDGET_CHECKBOX:
  998. newParam = new CheckBoxParam();
  999. oldParam.CopyTo(newParam);
  1000. break;
  1001. case C_WIDGET_TYPE.WIDGET_COMBOBOX:
  1002. newParam = new ComboBoxParam();
  1003. oldParam.CopyTo(newParam);
  1004. break;
  1005. case C_WIDGET_TYPE.WIDGET_LISTBOX:
  1006. newParam = new ListBoxParam();
  1007. oldParam.CopyTo(newParam);
  1008. break;
  1009. case C_WIDGET_TYPE.WIDGET_PUSHBUTTON:
  1010. newParam = new PushButtonParam();
  1011. oldParam.CopyTo(newParam);
  1012. break;
  1013. case C_WIDGET_TYPE.WIDGET_RADIOBUTTON:
  1014. newParam = new RadioButtonParam();
  1015. oldParam.CopyTo(newParam);
  1016. break;
  1017. case C_WIDGET_TYPE.WIDGET_SIGNATUREFIELDS:
  1018. newParam = new SignatureParam();
  1019. oldParam.CopyTo(newParam);
  1020. break;
  1021. case C_WIDGET_TYPE.WIDGET_TEXTFIELD:
  1022. newParam = new TextBoxParam();
  1023. oldParam.CopyTo(newParam);
  1024. break;
  1025. default:
  1026. return null;
  1027. }
  1028. }
  1029. break;
  1030. default:
  1031. return null;
  1032. }
  1033. return newParam;
  1034. }
  1035. return null;
  1036. }
  1037. }
  1038. }