CPDFViewerTool.AnnotSelector.cs 45 KB

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