RulerPro.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. using PaintDotNet.SystemLayer;
  2. using System;
  3. using System.ComponentModel;
  4. using System.Drawing;
  5. using System.Drawing.Drawing2D;
  6. using System.Windows.Forms;
  7. namespace PaintDotNet
  8. {
  9. /// <summary>
  10. /// 顶部和左侧的标尺控件
  11. /// </summary>
  12. public sealed class RulerPro : UserControl
  13. {
  14. /// <summary>
  15. /// 默认单位,英寸
  16. /// </summary>
  17. private MeasurementUnit measurementUnit = MeasurementUnit.Inch;
  18. public MeasurementUnit MeasurementUnit
  19. {
  20. get
  21. {
  22. return measurementUnit;
  23. }
  24. set
  25. {
  26. if (value != measurementUnit)
  27. {
  28. measurementUnit = value;
  29. Invalidate();
  30. }
  31. }
  32. }
  33. /// <summary>
  34. /// 默认方向 水平
  35. /// </summary>
  36. private Orientation orientation = Orientation.Horizontal;
  37. [DefaultValue(Orientation.Horizontal)]
  38. public Orientation Orientation
  39. {
  40. get
  41. {
  42. return orientation;
  43. }
  44. set
  45. {
  46. if (orientation != value)
  47. {
  48. orientation = value;
  49. Invalidate();
  50. }
  51. }
  52. }
  53. /// <summary>
  54. /// 每英寸长度内的像素点数
  55. /// 默认写死的dpi,96没有实际意义
  56. /// 需要从标尺读取
  57. /// </summary>
  58. private double dpu = 96;
  59. [DefaultValue(96.0)]
  60. public double Dpu
  61. {
  62. get
  63. {
  64. return dpu;
  65. }
  66. set
  67. {
  68. if (value != dpu)
  69. {
  70. dpu = value;
  71. Invalidate();
  72. }
  73. }
  74. }
  75. /// <summary>
  76. /// 封装了缩放功能的结构体
  77. /// </summary>
  78. private ScaleFactor scaleFactor = ScaleFactor.OneToOne;
  79. [Browsable(false)]
  80. public ScaleFactor ScaleFactor
  81. {
  82. get
  83. {
  84. return scaleFactor;
  85. }
  86. set
  87. {
  88. if (scaleFactor != value)
  89. {
  90. scaleFactor = value;
  91. Invalidate();
  92. }
  93. }
  94. }
  95. private float offset = 0;
  96. [DefaultValue(0)]
  97. public float Offset
  98. {
  99. get
  100. {
  101. return offset;
  102. }
  103. set
  104. {
  105. if (offset != value)
  106. {
  107. offset = value;
  108. Invalidate();
  109. }
  110. }
  111. }
  112. private float rulerValue = 0.0f;
  113. [DefaultValue(0)]
  114. public float Value
  115. {
  116. get
  117. {
  118. return rulerValue;
  119. }
  120. set
  121. {
  122. if (this.rulerValue != value)
  123. {
  124. float oldStart = this.scaleFactor.ScaleScalar(this.rulerValue - offset) - 1;
  125. float oldEnd = this.scaleFactor.ScaleScalar(this.rulerValue + 1 - offset) + 1;
  126. RectangleF oldRect;
  127. if (this.orientation == Orientation.Horizontal)
  128. {
  129. oldRect = new RectangleF(oldStart, this.ClientRectangle.Top, oldEnd - oldStart, this.ClientRectangle.Height);
  130. }
  131. else // if (this.orientation == Orientation.Vertical)
  132. {
  133. oldRect = new RectangleF(this.ClientRectangle.Left, oldStart, this.ClientRectangle.Width, oldEnd - oldStart);
  134. }
  135. float newStart = this.scaleFactor.ScaleScalar(value - offset);
  136. float newEnd = this.scaleFactor.ScaleScalar(value + 1 - offset);
  137. RectangleF newRect;
  138. if (this.orientation == Orientation.Horizontal)
  139. {
  140. newRect = new RectangleF(newStart, this.ClientRectangle.Top, newEnd - newStart, this.ClientRectangle.Height);
  141. }
  142. else // if (this.orientation == Orientation.Vertical)
  143. {
  144. newRect = new RectangleF(this.ClientRectangle.Left, newStart, this.ClientRectangle.Width, newEnd - newStart);
  145. }
  146. this.rulerValue = value;
  147. Invalidate(Utility.RoundRectangle(oldRect));
  148. Invalidate(Utility.RoundRectangle(newRect));
  149. }
  150. }
  151. }
  152. private float highlightStart = 2048.0f;
  153. public float HighlightStart
  154. {
  155. get
  156. {
  157. return this.highlightStart;
  158. }
  159. set
  160. {
  161. if (this.highlightStart != value)
  162. {
  163. this.highlightStart = value;
  164. Invalidate();
  165. }
  166. }
  167. }
  168. private float highlightLength = 2448.0f;
  169. public float HighlightLength
  170. {
  171. get
  172. {
  173. return this.highlightLength;
  174. }
  175. set
  176. {
  177. if (this.highlightLength != value)
  178. {
  179. this.highlightLength = value;
  180. Invalidate();
  181. }
  182. }
  183. }
  184. /// <summary>
  185. /// 构造方法
  186. /// </summary>
  187. public RulerPro()
  188. {
  189. SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
  190. }
  191. protected override void OnPaint(PaintEventArgs e)
  192. {
  193. float highlightStartPx = this.scaleFactor.ScaleScalar(this.highlightStart - offset);
  194. float highlightEndPx = this.scaleFactor.ScaleScalar(this.highlightStart + this.highlightLength - offset);
  195. RectangleF highlightRect;
  196. var hilitBrush = new SolidBrush(Color.FromArgb(128, 128, 128, 128));
  197. var hilitPen = new Pen(Color.FromArgb(200, 128, 128, 128));
  198. if (this.orientation == Orientation.Horizontal)
  199. {
  200. e.Graphics.DrawLine(SystemPens.WindowText, UI.ScaleWidth(Height - 1), ClientRectangle.Top, UI.ScaleWidth(Height - 1), ClientRectangle.Bottom);
  201. DrawRuler(e);
  202. highlightRect = new RectangleF(highlightStartPx, this.ClientRectangle.Top, highlightEndPx - highlightStartPx, this.ClientRectangle.Height - 11);
  203. e.Graphics.FillRectangle(hilitBrush, highlightRect);
  204. e.Graphics.DrawRectangle(hilitPen, Rectangle.Round(highlightRect));
  205. }
  206. else if (this.orientation == Orientation.Vertical)
  207. {
  208. highlightRect = new RectangleF(this.ClientRectangle.Left, highlightStartPx, this.ClientRectangle.Width - 11, highlightEndPx - highlightStartPx);
  209. DrawRuler(e);
  210. e.Graphics.FillRectangle(hilitBrush, highlightRect);
  211. e.Graphics.DrawRectangle(hilitPen, Rectangle.Round(highlightRect));
  212. }
  213. }
  214. private static readonly float[] majorDivisors =
  215. new float[]
  216. {
  217. 5.0f,
  218. 4.0f,
  219. 5.0f,
  220. 4.0f,
  221. 5.0f,
  222. };
  223. private int[] GetSubdivs(MeasurementUnit unit)
  224. {
  225. switch (unit)
  226. {
  227. case MeasurementUnit.Inch:
  228. {
  229. return new int[] { 2 };
  230. }
  231. case MeasurementUnit.Mil:
  232. {
  233. return new int[] { 2 };
  234. }
  235. case MeasurementUnit.Centimeter:
  236. {
  237. return new int[] { 2 };
  238. }
  239. case MeasurementUnit.Millimeter:
  240. {
  241. return new int[] { 2 };
  242. }
  243. case MeasurementUnit.Micron:
  244. {
  245. return new int[] { 2 };
  246. }
  247. case MeasurementUnit.Nano:
  248. {
  249. return new int[] { 2 };
  250. }
  251. default:
  252. {
  253. return null;
  254. }
  255. }
  256. }
  257. /// <summary>
  258. /// 分割x轴
  259. /// </summary>
  260. /// <param name="g"></param>
  261. /// <param name="pen"></param>
  262. /// <param name="x"></param>
  263. /// <param name="delta"></param>
  264. /// <param name="index"></param>
  265. /// <param name="y"></param>
  266. /// <param name="height"></param>
  267. /// <param name="subdivs"></param>
  268. private void SubdivideX(
  269. Graphics g,
  270. Pen pen,
  271. float x,
  272. float delta,
  273. int index,
  274. float y,
  275. float height,
  276. int[] subdivs)
  277. {
  278. g.DrawLine(pen, x, y, x, y + height);
  279. if (index > 10)
  280. {
  281. return;
  282. }
  283. float div;
  284. if (subdivs != null && index >= 0)
  285. {
  286. div = subdivs[index % subdivs.Length];
  287. }
  288. else if (index < 0)
  289. {
  290. div = majorDivisors[(-index - 1) % majorDivisors.Length];
  291. }
  292. else
  293. {
  294. return;
  295. }
  296. for (int i = 0; i < div; i++)
  297. {
  298. if ((delta / div) > 3.5)
  299. {
  300. SubdivideX(g, pen, x + delta * i / div, delta / div, index + 1, y, height / div + 0.5f, subdivs);
  301. }
  302. }
  303. }
  304. /// <summary>
  305. /// 分割y轴
  306. /// </summary>
  307. /// <param name="g"></param>
  308. /// <param name="pen"></param>
  309. /// <param name="y"></param>
  310. /// <param name="delta"></param>
  311. /// <param name="index"></param>
  312. /// <param name="x"></param>
  313. /// <param name="width"></param>
  314. /// <param name="subdivs"></param>
  315. private void SubdivideY(
  316. Graphics g,
  317. Pen pen,
  318. float y,
  319. float delta,
  320. int index,
  321. float x,
  322. float width,
  323. int[] subdivs)
  324. {
  325. g.DrawLine(pen, x, y, x + width, y);
  326. if (index > 10)
  327. {
  328. return;
  329. }
  330. float div;
  331. if (subdivs != null && index >= 0)
  332. {
  333. div = subdivs[index % subdivs.Length];
  334. }
  335. else if (index < 0)
  336. {
  337. div = majorDivisors[(-index - 1) % majorDivisors.Length];
  338. }
  339. else
  340. {
  341. return;
  342. }
  343. for (int i = 0; i < div; i++)
  344. {
  345. if ((delta / div) > 3.5)
  346. {
  347. SubdivideY(g, pen, y + delta * i / div, delta / div, index + 1, x, width / div + 0.5f, subdivs);
  348. }
  349. }
  350. }
  351. /// <summary>
  352. /// 绘制标尺
  353. /// </summary>
  354. /// <param name="e"></param>
  355. /// <param name="highlighted"></param>
  356. private void DrawRuler(PaintEventArgs e)
  357. {
  358. Pen pen;
  359. Brush cursorBrush;
  360. Brush textBrush;
  361. StringFormat textFormat = new StringFormat();
  362. int maxPixel;
  363. Color cursorColor;
  364. pen = SystemPens.WindowText;
  365. textBrush = SystemBrushes.WindowText;
  366. cursorColor = SystemColors.Highlight;
  367. cursorColor = Color.FromArgb(128, cursorColor);
  368. cursorBrush = new SolidBrush(cursorColor);
  369. if (orientation == Orientation.Horizontal)
  370. {
  371. maxPixel = ScaleFactor.UnscaleScalar(ClientRectangle.Width);
  372. textFormat.Alignment = StringAlignment.Near;
  373. textFormat.LineAlignment = StringAlignment.Far;
  374. }
  375. else // if (orientation == Orientation.Vertical)
  376. {
  377. maxPixel = ScaleFactor.UnscaleScalar(ClientRectangle.Height);
  378. textFormat.Alignment = StringAlignment.Near;
  379. textFormat.LineAlignment = StringAlignment.Near;
  380. textFormat.FormatFlags |= StringFormatFlags.DirectionVertical;
  381. }
  382. float majorSkip = 1f;
  383. int majorSkipPower = 0;
  384. float majorDivisionLength = (float)dpu;
  385. float majorDivisionPixels = (float)ScaleFactor.ScaleScalar(majorDivisionLength);
  386. int[] subdivs = GetSubdivs(measurementUnit);
  387. float offsetPixels = ScaleFactor.ScaleScalar((float)offset);
  388. int startMajor = (int)(offset / majorDivisionLength) - 1;
  389. int endMajor = (int)((offset + maxPixel) / majorDivisionLength) + 1;
  390. if (orientation == Orientation.Horizontal)
  391. {
  392. PointF pt = scaleFactor.ScalePointJustX(new PointF(ClientRectangle.Left + Value - Offset, ClientRectangle.Top));
  393. SizeF size = new SizeF(Math.Max(1, scaleFactor.ScaleScalar(1.0f)), ClientRectangle.Height);
  394. pt.X -= 0.5f;
  395. CompositingMode oldCM = e.Graphics.CompositingMode;
  396. e.Graphics.CompositingMode = CompositingMode.SourceOver;
  397. e.Graphics.FillRectangle(cursorBrush, new RectangleF(pt, size));
  398. e.Graphics.CompositingMode = oldCM;
  399. // draw border
  400. e.Graphics.DrawLine(SystemPens.WindowText, new Point(ClientRectangle.Left, ClientRectangle.Bottom - 1),
  401. new Point(ClientRectangle.Right - 1, ClientRectangle.Bottom - 1));
  402. }
  403. else if (orientation == Orientation.Vertical)
  404. {
  405. PointF pt = scaleFactor.ScalePointJustY(new PointF(ClientRectangle.Left, ClientRectangle.Top + Value - Offset));
  406. SizeF size = new SizeF(ClientRectangle.Width, Math.Max(1, scaleFactor.ScaleScalar(1.0f)));
  407. pt.Y -= 0.5f;
  408. CompositingMode oldCM = e.Graphics.CompositingMode;
  409. e.Graphics.CompositingMode = CompositingMode.SourceOver;
  410. e.Graphics.FillRectangle(cursorBrush, new RectangleF(pt, size));
  411. e.Graphics.CompositingMode = oldCM;
  412. // draw border
  413. e.Graphics.DrawLine(SystemPens.WindowText, new Point(ClientRectangle.Right - 1, ClientRectangle.Top),
  414. new Point(ClientRectangle.Right - 1, ClientRectangle.Bottom - 1));
  415. }
  416. while (majorDivisionPixels * majorSkip < 100)
  417. {
  418. majorSkip *= majorDivisors[majorSkipPower % majorDivisors.Length];
  419. ++majorSkipPower;
  420. }
  421. startMajor = (int)Math.Round((majorSkip * Math.Floor(startMajor / (double)majorSkip)));
  422. for (float major = startMajor; major <= endMajor; major += majorSkip)//skip
  423. {
  424. float majorMarkPos = ((float)major * majorDivisionPixels) - offsetPixels;
  425. string majorText = major.ToString();
  426. if (orientation == Orientation.Horizontal)
  427. {
  428. SubdivideX(e.Graphics, pen, ClientRectangle.Left + majorMarkPos, majorDivisionPixels * majorSkip, -majorSkipPower, ClientRectangle.Top, ClientRectangle.Height, subdivs);
  429. e.Graphics.DrawString(majorText, Font, textBrush, new PointF(ClientRectangle.Left + majorMarkPos, ClientRectangle.Bottom), textFormat);
  430. }
  431. else // if (orientation == Orientation.Vertical)
  432. {
  433. SubdivideY(e.Graphics, pen, ClientRectangle.Top + majorMarkPos, majorDivisionPixels * majorSkip, -majorSkipPower, ClientRectangle.Left, ClientRectangle.Width, subdivs);
  434. e.Graphics.DrawString(majorText, Font, textBrush, new PointF(ClientRectangle.Left, ClientRectangle.Top + majorMarkPos), textFormat);
  435. }
  436. }
  437. //
  438. // 以下是绘制文字
  439. //
  440. decimal skip = this.SkipNumberCalc(measurementUnit);
  441. int k = 0;
  442. int f = this.SkipInterval(measurementUnit);
  443. for (decimal major = startMajor; major <= endMajor; major += skip)//majorSkip
  444. {
  445. //float majorMarkPos = ((float)major * majorDivisionPixels) - offsetPixels;
  446. //string majorText = major.ToString();//(Math.Round(Convert.ToDecimal(major), 4, MidpointRounding.AwayFromZero)).ToString();
  447. //if (orientation == Orientation.Horizontal)
  448. //{
  449. // if (k % f == 0)
  450. // {
  451. // e.Graphics.DrawString(majorText, Font, textBrush, new PointF(ClientRectangle.Left + majorMarkPos, ClientRectangle.Bottom), textFormat);
  452. // }
  453. //}
  454. //else // if (orientation == Orientation.Vertical)
  455. //{
  456. // if (k % f == 0)
  457. // {
  458. // e.Graphics.DrawString(majorText, Font, textBrush, new PointF(ClientRectangle.Left, ClientRectangle.Top + majorMarkPos), textFormat);
  459. // }
  460. //}
  461. k++;
  462. }
  463. textFormat.Dispose();
  464. }
  465. /// <summary>
  466. /// 根据不同单位返回不同的间隔长度
  467. /// </summary>
  468. /// <param name="unit"></param>
  469. /// <returns></returns>
  470. private decimal SkipNumberCalc(MeasurementUnit unit)
  471. {
  472. decimal skip = 100M;
  473. if (unit == MeasurementUnit.Inch)
  474. {
  475. skip = 0.001M;
  476. }
  477. else if (unit == MeasurementUnit.Mil)
  478. {
  479. skip = 0.1M;//###Mil
  480. }
  481. else if (unit == MeasurementUnit.Centimeter)
  482. {
  483. skip = 0.01M;
  484. }
  485. else if (unit == MeasurementUnit.Millimeter)
  486. {
  487. skip = 0.1M;
  488. }
  489. else if (unit == MeasurementUnit.Micron)
  490. {
  491. skip = 10M;
  492. }
  493. else if (unit == MeasurementUnit.Nano)
  494. {
  495. skip = 10000M;
  496. }
  497. return skip;
  498. }
  499. /// <summary>
  500. /// 不同的缩放比列下,间隔多少单元格绘制文字
  501. /// </summary>
  502. /// <param name="unit"></param>
  503. /// <returns></returns>
  504. private int SkipInterval(MeasurementUnit unit)
  505. {
  506. int f = 1;
  507. if (scaleFactor.Ratio <= 0.05f)
  508. {
  509. switch (unit)
  510. {
  511. case MeasurementUnit.Pixel:
  512. case MeasurementUnit.Centimeter:
  513. case MeasurementUnit.Millimeter:
  514. f = 100;
  515. break;
  516. case MeasurementUnit.Inch:
  517. case MeasurementUnit.Mil://###Mil
  518. case MeasurementUnit.Micron:
  519. case MeasurementUnit.Nano:
  520. f = 1000;
  521. break;
  522. }
  523. }
  524. else if (scaleFactor.Ratio <= 0.1f)
  525. {
  526. switch (unit)
  527. {
  528. case MeasurementUnit.Pixel:
  529. case MeasurementUnit.Centimeter:
  530. case MeasurementUnit.Millimeter:
  531. f = 10;
  532. break;
  533. case MeasurementUnit.Inch:
  534. case MeasurementUnit.Mil://###Mil
  535. case MeasurementUnit.Micron:
  536. case MeasurementUnit.Nano:
  537. f = 100;
  538. break;
  539. }
  540. }
  541. else if (scaleFactor.Ratio <= 0.5f)
  542. {
  543. switch (unit)
  544. {
  545. case MeasurementUnit.Pixel:
  546. case MeasurementUnit.Centimeter:
  547. case MeasurementUnit.Millimeter:
  548. f = 5;
  549. break;
  550. case MeasurementUnit.Inch:
  551. case MeasurementUnit.Mil://###Mil
  552. case MeasurementUnit.Micron:
  553. case MeasurementUnit.Nano:
  554. f = 50;
  555. break;
  556. }
  557. }
  558. else
  559. {
  560. switch (unit)
  561. {
  562. case MeasurementUnit.Pixel:
  563. case MeasurementUnit.Centimeter:
  564. case MeasurementUnit.Millimeter:
  565. f = 1;
  566. break;
  567. case MeasurementUnit.Inch:
  568. case MeasurementUnit.Mil://###Mil
  569. case MeasurementUnit.Micron:
  570. case MeasurementUnit.Nano:
  571. f = 10;
  572. break;
  573. }
  574. }
  575. return f;
  576. }
  577. }
  578. }