GradientTool.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. using PaintDotNet.Measurement.HistoryMementos;
  2. using PaintDotNet.SystemLayer;
  3. using System;
  4. using System.Drawing;
  5. using System.Drawing.Drawing2D;
  6. using System.Threading;
  7. using System.Windows.Forms;
  8. namespace PaintDotNet.Measurement.Tools
  9. {
  10. public sealed class GradientTool : Tool
  11. {
  12. public static string StaticName
  13. {
  14. get
  15. {
  16. return PdnResources.GetString("GradientTool.Name");
  17. }
  18. }
  19. public static ImageResource StaticImage
  20. {
  21. get
  22. {
  23. return PdnResources.GetImageResource("Icons.GradientToolIcon.png");
  24. }
  25. }
  26. private Cursor toolCursor;
  27. private Cursor toolMouseDownCursor;
  28. private ImageResource toolIcon;
  29. private MoveNubRenderer[] moveNubs;
  30. private MoveNubRenderer startNub;
  31. private MoveNubRenderer endNub;
  32. private MoveNubRenderer mouseNub; // which nub the mouse is manipulating, null for neither
  33. private MouseButtons mouseButton = MouseButtons.None;
  34. private PointF startPoint;
  35. private PointF endPoint;
  36. private string helpTextInitial = PdnResources.GetString("GradientTool.HelpText");
  37. private string helpTextWhileAdjustingFormat = PdnResources.GetString("GradientTool.HelpText.WhileAdjusting.Format");
  38. private string helpTextAdjustable = PdnResources.GetString("GradientTool.HelpText.Adjustable");
  39. private bool shouldMoveBothNubs = false;
  40. private bool shouldConstrain = false;
  41. private bool shouldSwapColors = false;
  42. private bool gradientActive = false; // we are drawing or adjusting a gradient
  43. private CompoundHistoryMemento historyMemento = null;
  44. private void ConstrainPoints(PointF a, ref PointF b)
  45. {
  46. PointF dir = new PointF(b.X - a.X, b.Y - a.Y);
  47. double theta = Math.Atan2(dir.Y, dir.X);
  48. double len = Math.Sqrt(dir.X * dir.X + dir.Y * dir.Y);
  49. theta = Math.Round(12 * theta / Math.PI) * Math.PI / 12;
  50. b = new PointF((float)(a.X + len * Math.Cos(theta)), (float)(a.Y + len * Math.Sin(theta)));
  51. }
  52. protected override void OnPulse()
  53. {
  54. if (this.gradientActive && this.moveNubs != null)
  55. {
  56. for (int i = 0; i < this.moveNubs.Length; ++i)
  57. {
  58. if (!this.moveNubs[i].Visible)
  59. {
  60. continue;
  61. }
  62. // Oscillate between 25% and 100% alpha over a period of 2 seconds
  63. // Alpha value of 100% is sustained for a large duration of this period
  64. const int period = 10000 * 2000; // 10000 ticks per ms, 2000ms per second
  65. long tick = (DateTime.Now.Ticks % period) + (i * (period / this.moveNubs.Length)); ;
  66. double sin = Math.Sin(((double)tick / (double)period) * (2.0 * Math.PI));
  67. // sin is [-1, +1]
  68. sin = Math.Min(0.5, sin);
  69. // sin is [-1, +0.5]
  70. sin += 1.0;
  71. // sin is [0, 1.5]
  72. sin /= 2.0;
  73. // sin is [0, 0.75]
  74. sin += 0.25;
  75. // sin is [0.25, 1]
  76. int newAlpha = (int)(sin * 255.0);
  77. int clampedAlpha = Utility.Clamp(newAlpha, 0, 255);
  78. this.moveNubs[i].Alpha = clampedAlpha;
  79. }
  80. }
  81. base.OnPulse();
  82. }
  83. private bool controlKeyDown = false;
  84. private DateTime controlKeyDownTime = DateTime.MinValue;
  85. private readonly TimeSpan controlKeyDownThreshold = new TimeSpan(0, 0, 0, 0, 400);
  86. protected override void OnKeyDown(KeyEventArgs e)
  87. {
  88. switch (e.KeyCode)
  89. {
  90. case Keys.ControlKey:
  91. if (!this.controlKeyDown)
  92. {
  93. this.controlKeyDown = true;
  94. this.controlKeyDownTime = DateTime.Now;
  95. }
  96. break;
  97. case Keys.ShiftKey:
  98. bool oldShouldConstrain = this.shouldConstrain;
  99. this.shouldConstrain = true;
  100. if (this.gradientActive &&
  101. this.mouseButton != MouseButtons.None &&
  102. !oldShouldConstrain)
  103. {
  104. RenderGradient();
  105. }
  106. break;
  107. }
  108. base.OnKeyDown(e);
  109. }
  110. protected override void OnKeyUp(KeyEventArgs e)
  111. {
  112. switch (e.KeyCode)
  113. {
  114. case Keys.ControlKey:
  115. TimeSpan heldDuration = (DateTime.Now - this.controlKeyDownTime);
  116. // If the user taps Ctrl, then we should toggle the visiblity of the moveNubs
  117. if (heldDuration < this.controlKeyDownThreshold)
  118. {
  119. for (int i = 0; i < this.moveNubs.Length; ++i)
  120. {
  121. this.moveNubs[i].Visible = this.gradientActive && !this.moveNubs[i].Visible;
  122. }
  123. }
  124. this.controlKeyDown = false;
  125. break;
  126. case Keys.ShiftKey:
  127. this.shouldConstrain = false;
  128. if (this.gradientActive &&
  129. this.mouseButton != MouseButtons.None)
  130. {
  131. RenderGradient();
  132. }
  133. break;
  134. }
  135. base.OnKeyUp(e);
  136. }
  137. protected override void OnKeyPress(KeyPressEventArgs e)
  138. {
  139. if (this.gradientActive)
  140. {
  141. switch (e.KeyChar)
  142. {
  143. case '\r': // Enter
  144. e.Handled = true;
  145. CommitGradient();
  146. break;
  147. case (char)27: // Escape
  148. e.Handled = true;
  149. CommitGradient();
  150. //HistoryStack.StepBackward();
  151. break;
  152. }
  153. }
  154. base.OnKeyPress(e);
  155. }
  156. private sealed class RenderContext
  157. {
  158. public Surface surface;
  159. public Rectangle[] rois;
  160. public GradientRenderer renderer;
  161. public void Render(object cpuIndexObj)
  162. {
  163. int cpuIndex = (int)cpuIndexObj;
  164. int start = (this.rois.Length * cpuIndex) / Processor.LogicalCpuCount;
  165. int end = (this.rois.Length * (cpuIndex + 1)) / Processor.LogicalCpuCount;
  166. renderer.Render(this.surface, this.rois, start, end - start);
  167. }
  168. }
  169. private void RenderGradient(Surface surface, PdnRegion clipRegion, CompositingMode compositingMode,
  170. PointF startPointF, ColorBgra startColor, PointF endPointF, ColorBgra endColor)
  171. {
  172. GradientRenderer gr = AppEnvironment.GradientInfo().CreateGradientRenderer();
  173. gr.StartColor = startColor;
  174. gr.EndColor = endColor;
  175. gr.StartPoint = startPointF;
  176. gr.EndPoint = endPointF;
  177. gr.AlphaBlending = (compositingMode == CompositingMode.SourceOver);
  178. gr.BeforeRender();
  179. Rectangle[] oldRois = clipRegion.GetRegionScansReadOnlyInt();
  180. Rectangle[] newRois;
  181. if (oldRois.Length == 1)
  182. {
  183. newRois = new Rectangle[Processor.LogicalCpuCount];
  184. Utility.SplitRectangle(oldRois[0], newRois);
  185. }
  186. else
  187. {
  188. newRois = oldRois;
  189. }
  190. RenderContext rc = new RenderContext();
  191. rc.surface = surface;
  192. rc.rois = newRois;
  193. rc.renderer = gr;
  194. WaitCallback wc = new WaitCallback(rc.Render);
  195. for (int i = 0; i < Processor.LogicalCpuCount; ++i)
  196. {
  197. if (i == Processor.LogicalCpuCount - 1)
  198. {
  199. wc(BoxedConstants.GetInt32(i));
  200. }
  201. else
  202. {
  203. PaintDotNet.Threading.ThreadPool.Global.QueueUserWorkItem(wc, BoxedConstants.GetInt32(i));
  204. }
  205. }
  206. PaintDotNet.Threading.ThreadPool.Global.Drain();
  207. }
  208. private void RenderGradient()
  209. {
  210. ColorBgra startColor = AppEnvironment.PrimaryColor();
  211. ColorBgra endColor = AppEnvironment.SecondaryColor();
  212. if (this.shouldSwapColors)
  213. {
  214. if (AppEnvironment.GradientInfo().AlphaOnly)
  215. {
  216. // In transparency mode, the color values don't matter. We just need to reverse
  217. // and invert the alpha values.
  218. byte startAlpha = startColor.A;
  219. startColor.A = (byte)(255 - endColor.A);
  220. endColor.A = (byte)(255 - startAlpha);
  221. }
  222. else
  223. {
  224. Utility.Swap(ref startColor, ref endColor);
  225. }
  226. }
  227. PointF startPointF = this.startPoint;
  228. PointF endPointF = this.endPoint;
  229. if (this.shouldConstrain)
  230. {
  231. if (this.mouseNub == this.startNub)
  232. {
  233. ConstrainPoints(endPointF, ref startPointF);
  234. }
  235. else
  236. {
  237. ConstrainPoints(startPointF, ref endPointF);
  238. }
  239. }
  240. RestoreSavedRegion();
  241. Surface surface = ((BitmapLayer)DocumentWorkspace.GetActiveLayer()).Surface;
  242. PdnRegion clipRegion = DocumentWorkspace.GetSelection().CreateRegion();
  243. SaveRegion(clipRegion, clipRegion.GetBoundsInt());
  244. RenderGradient(surface, clipRegion, AppEnvironment.GetCompositingMode(), startPointF, startColor, endPointF, endColor);
  245. using (PdnRegion simplified = Utility.SimplifyAndInflateRegion(clipRegion, Utility.DefaultSimplificationFactor, 0))
  246. {
  247. DocumentWorkspace.GetActiveLayer().Invalidate(simplified);
  248. }
  249. clipRegion.Dispose();
  250. // Set up status bar text
  251. double angle = -180.0 * Math.Atan2(endPointF.Y - startPointF.Y, endPointF.X - startPointF.X) / Math.PI;
  252. MeasurementUnit units = AppWorkspace.GetUnits();
  253. double offsetXPhysical = Document.PixelToPhysicalX(endPointF.X - startPointF.X, units);
  254. double offsetYPhysical = Document.PixelToPhysicalY(endPointF.Y - startPointF.Y, units);
  255. double offsetLengthPhysical = Math.Sqrt(offsetXPhysical * offsetXPhysical + offsetYPhysical * offsetYPhysical);
  256. string numberFormat;
  257. string unitsAbbreviation;
  258. if (units != MeasurementUnit.Pixel)
  259. {
  260. string unitsAbbreviationName = "MeasurementUnit." + units.ToString() + ".Abbreviation";
  261. unitsAbbreviation = PdnResources.GetString(unitsAbbreviationName);
  262. numberFormat = "F2";
  263. }
  264. else
  265. {
  266. unitsAbbreviation = string.Empty;
  267. numberFormat = "F0";
  268. }
  269. string unitsString = PdnResources.GetString("MeasurementUnit." + units.ToString() + ".Plural");
  270. string statusText = string.Format(
  271. this.helpTextWhileAdjustingFormat,
  272. offsetXPhysical.ToString(numberFormat),
  273. unitsAbbreviation,
  274. offsetYPhysical.ToString(numberFormat),
  275. unitsAbbreviation,
  276. offsetLengthPhysical.ToString("F2"),
  277. unitsString,
  278. angle.ToString("F2"));
  279. SetStatus(this.toolIcon, statusText);
  280. // Make sure everything is on screen.
  281. Update();
  282. }
  283. protected override void OnMouseDown(MouseEventArgs e)
  284. {
  285. PointF mousePt = new PointF(e.X, e.Y);
  286. MoveNubRenderer mouseCursorNub = PointToNub(mousePt);
  287. if (this.mouseButton != MouseButtons.None)
  288. {
  289. this.shouldMoveBothNubs = !this.shouldMoveBothNubs;
  290. }
  291. else
  292. {
  293. bool startNewGradient = true;
  294. this.mouseButton = e.Button;
  295. if (!this.gradientActive)
  296. {
  297. this.shouldSwapColors = (this.mouseButton == MouseButtons.Right);
  298. }
  299. else
  300. {
  301. this.shouldMoveBothNubs = false;
  302. // We are already in the process of drawing or adjusting a gradient.
  303. // Determine if they clicked to drag one of the nubs for adjusting.
  304. if (mouseCursorNub == null)
  305. {
  306. // No. Commit the old gradient and begin a new one.
  307. CommitGradient();
  308. startNewGradient = true;
  309. this.shouldSwapColors = (this.mouseButton == MouseButtons.Right);
  310. }
  311. else
  312. {
  313. // Yes. Continue adjusting the old gradient.
  314. Cursor = this.handCursorMouseDown;
  315. this.mouseNub = mouseCursorNub;
  316. this.mouseNub.Location = mousePt;
  317. if (this.mouseNub == this.startNub)
  318. {
  319. this.startPoint = mousePt;
  320. }
  321. else
  322. {
  323. this.endPoint = mousePt;
  324. }
  325. if (this.mouseButton == MouseButtons.Right)
  326. {
  327. this.shouldSwapColors = !this.shouldSwapColors;
  328. }
  329. RenderGradient();
  330. startNewGradient = false;
  331. }
  332. }
  333. if (startNewGradient)
  334. {
  335. // Brand new gradient. Set everything up.
  336. this.startPoint = mousePt;
  337. this.startNub.Location = mousePt;
  338. this.startNub.Visible = true;
  339. this.endNub.Location = mousePt;
  340. this.endNub.Visible = true;
  341. this.endPoint = mousePt;
  342. this.mouseNub = mouseCursorNub;
  343. Cursor = this.toolMouseDownCursor;
  344. this.gradientActive = true;
  345. ClearSavedRegion();
  346. RenderGradient();
  347. this.historyMemento = new CompoundHistoryMemento(StaticName, StaticImage);
  348. //HistoryStack.PushNewMemento(this.historyMemento); // this makes it so they can push Esc to undo
  349. }
  350. }
  351. base.OnMouseDown(e);
  352. }
  353. private MoveNubRenderer PointToNub(PointF mousePtF)
  354. {
  355. float startDistance = Utility.Distance(mousePtF, this.startNub.Location);
  356. float endDistance = Utility.Distance(mousePtF, this.endNub.Location);
  357. if (this.startNub.Visible &&
  358. startDistance < endDistance &&
  359. this.startNub.IsPointTouching(mousePtF, true))
  360. {
  361. return this.startNub;
  362. }
  363. else if (this.endNub.Visible &&
  364. this.endNub.IsPointTouching(mousePtF, true))
  365. {
  366. return this.endNub;
  367. }
  368. else
  369. {
  370. return null;
  371. }
  372. }
  373. protected override void OnMouseMove(MouseEventArgs e)
  374. {
  375. PointF mousePtF = new PointF(e.X, e.Y);
  376. MoveNubRenderer mouseCursorNub = PointToNub(mousePtF);
  377. if (this.mouseButton == MouseButtons.None)
  378. {
  379. // No mouse button dragging is being tracked.
  380. this.mouseNub = mouseCursorNub;
  381. if (this.mouseNub == this.startNub || this.mouseNub == this.endNub)
  382. {
  383. Cursor = this.handCursor;
  384. }
  385. else
  386. {
  387. Cursor = this.toolCursor;
  388. }
  389. }
  390. else
  391. {
  392. if (this.mouseNub == this.startNub)
  393. {
  394. // Dragging the start nub
  395. if (this.shouldConstrain && !this.shouldMoveBothNubs)
  396. {
  397. ConstrainPoints(this.endPoint, ref mousePtF);
  398. }
  399. this.startNub.Location = mousePtF;
  400. SizeF delta = new SizeF(
  401. this.startNub.Location.X - this.startPoint.X,
  402. this.startNub.Location.Y - this.startPoint.Y);
  403. this.startPoint = mousePtF;
  404. if (this.shouldMoveBothNubs)
  405. {
  406. this.endNub.Location += delta;
  407. this.endPoint += delta;
  408. }
  409. }
  410. else if (this.mouseNub == this.endNub)
  411. {
  412. // Dragging the ending nub
  413. if (this.shouldConstrain && !this.shouldMoveBothNubs)
  414. {
  415. ConstrainPoints(this.startPoint, ref mousePtF);
  416. }
  417. this.endNub.Location = mousePtF;
  418. SizeF delta = new SizeF(
  419. this.endNub.Location.X - this.endPoint.X,
  420. this.endNub.Location.Y - this.endPoint.Y);
  421. this.endPoint = mousePtF;
  422. if (this.shouldMoveBothNubs)
  423. {
  424. this.startNub.Location += delta;
  425. this.startPoint += delta;
  426. }
  427. }
  428. else
  429. {
  430. // Initial drawing
  431. if (this.shouldMoveBothNubs)
  432. {
  433. SizeF delta = new SizeF(
  434. this.endNub.Location.X - mousePtF.X,
  435. this.endNub.Location.Y - mousePtF.Y);
  436. this.startNub.Location -= delta;
  437. this.startPoint -= delta;
  438. }
  439. else if (this.shouldConstrain)
  440. {
  441. ConstrainPoints(this.startPoint, ref mousePtF);
  442. }
  443. this.endNub.Location = mousePtF;
  444. this.endPoint = mousePtF;
  445. }
  446. RenderGradient();
  447. }
  448. base.OnMouseMove(e);
  449. }
  450. private void CommitGradient()
  451. {
  452. if (!this.gradientActive)
  453. {
  454. throw new InvalidOperationException("CommitGradient() called when a gradient was not active");
  455. }
  456. RenderGradient();
  457. using (PdnRegion clipRegion = DocumentWorkspace.GetSelection().CreateRegion())
  458. {
  459. BitmapHistoryMemento bhm = new BitmapHistoryMemento(
  460. StaticName,
  461. StaticImage,
  462. DocumentWorkspace,
  463. DocumentWorkspace.GetActiveLayerIndex(),
  464. clipRegion,
  465. this.ScratchSurface);
  466. this.historyMemento.PushNewAction(bhm);
  467. // We assume this.historyMemento has already been pushed on to the HistoryStack
  468. this.historyMemento = null;
  469. }
  470. this.startNub.Visible = false;
  471. this.endNub.Visible = false;
  472. ClearSavedRegion();
  473. ClearSavedMemory();
  474. this.gradientActive = false;
  475. SetStatus(this.toolIcon, this.helpTextInitial);
  476. }
  477. protected override void OnMouseUp(MouseEventArgs e)
  478. {
  479. PointF mousePt = new PointF(e.X, e.Y);
  480. if (!this.gradientActive)
  481. {
  482. // do nothing
  483. }
  484. else if (e.Button != this.mouseButton)
  485. {
  486. this.shouldMoveBothNubs = !this.shouldMoveBothNubs;
  487. }
  488. else
  489. {
  490. if (this.mouseNub == this.startNub)
  491. {
  492. // We were adjusting the start nub.
  493. if (this.shouldConstrain)
  494. {
  495. ConstrainPoints(this.endPoint, ref mousePt);
  496. }
  497. this.startNub.Location = mousePt;
  498. this.startPoint = mousePt;
  499. }
  500. else if (this.mouseNub == this.endNub)
  501. {
  502. // We were adjusting the ending nub.
  503. if (this.shouldConstrain)
  504. {
  505. ConstrainPoints(this.startPoint, ref mousePt);
  506. }
  507. this.endNub.Location = mousePt;
  508. this.endPoint = mousePt;
  509. }
  510. else
  511. {
  512. // We were drawing a brand new gradient.
  513. if (this.shouldConstrain)
  514. {
  515. ConstrainPoints(this.startPoint, ref mousePt);
  516. }
  517. this.endNub.Location = mousePt;
  518. this.endPoint = mousePt;
  519. }
  520. // In any event, make sure the nubs are visible and other state adjusted accordingly.
  521. this.startNub.Visible = true;
  522. this.endNub.Visible = true;
  523. this.mouseButton = MouseButtons.None;
  524. this.gradientActive = true;
  525. SetStatus(this.toolIcon, this.helpTextAdjustable);
  526. }
  527. base.OnMouseUp(e);
  528. }
  529. private void RenderBecauseOfEvent(object sender, EventArgs e)
  530. {
  531. if (this.gradientActive)
  532. {
  533. RenderGradient();
  534. }
  535. }
  536. protected override void OnActivate()
  537. {
  538. this.toolCursor = new Cursor(PdnResources.GetResourceStream("Cursors.GenericToolCursor.cur"));
  539. this.toolMouseDownCursor = new Cursor(PdnResources.GetResourceStream("Cursors.GenericToolCursorMouseDown.cur"));
  540. this.Cursor = this.toolCursor;
  541. this.toolIcon = this.Image;
  542. this.startNub = new MoveNubRenderer(RendererList);
  543. this.startNub.Visible = false;
  544. this.startNub.Shape = MoveNubShape.Circle;
  545. RendererList.Add(this.startNub, false);
  546. this.endNub = new MoveNubRenderer(RendererList);
  547. this.endNub.Visible = false;
  548. this.endNub.Shape = MoveNubShape.Circle;
  549. RendererList.Add(this.endNub, false);
  550. this.moveNubs =
  551. new MoveNubRenderer[]
  552. {
  553. this.startNub,
  554. this.endNub
  555. };
  556. AppEnvironment.PrimaryColorChanged += new EventHandler(RenderBecauseOfEvent);
  557. AppEnvironment.SecondaryColorChanged += new EventHandler(RenderBecauseOfEvent);
  558. AppEnvironment.GradientInfoChanged += new EventHandler(RenderBecauseOfEvent);
  559. AppEnvironment.AlphaBlendingChanged += new EventHandler(RenderBecauseOfEvent);
  560. AppWorkspace.UnitsChanged += new EventHandler(RenderBecauseOfEvent);
  561. base.OnActivate();
  562. }
  563. protected override void OnDeactivate()
  564. {
  565. AppEnvironment.PrimaryColorChanged -= new EventHandler(RenderBecauseOfEvent);
  566. AppEnvironment.SecondaryColorChanged -= new EventHandler(RenderBecauseOfEvent);
  567. AppEnvironment.GradientInfoChanged -= new EventHandler(RenderBecauseOfEvent);
  568. AppEnvironment.AlphaBlendingChanged -= new EventHandler(RenderBecauseOfEvent);
  569. AppWorkspace.UnitsChanged -= new EventHandler(RenderBecauseOfEvent);
  570. if (this.gradientActive)
  571. {
  572. CommitGradient();
  573. this.mouseButton = MouseButtons.None;
  574. }
  575. if (this.startNub != null)
  576. {
  577. RendererList.Remove(this.startNub);
  578. this.startNub.Dispose();
  579. this.startNub = null;
  580. }
  581. if (this.endNub != null)
  582. {
  583. RendererList.Remove(this.endNub);
  584. this.endNub.Dispose();
  585. this.endNub = null;
  586. }
  587. this.moveNubs = null;
  588. if (this.toolCursor != null)
  589. {
  590. this.toolCursor.Dispose();
  591. this.toolCursor = null;
  592. }
  593. if (this.toolMouseDownCursor != null)
  594. {
  595. this.toolMouseDownCursor.Dispose();
  596. this.toolMouseDownCursor = null;
  597. }
  598. base.OnDeactivate();
  599. }
  600. public GradientTool(IDocumentWorkspace documentWorkspace)
  601. : base(documentWorkspace,
  602. StaticImage,
  603. StaticName,
  604. PdnResources.GetString("GradientTool.HelpText"),
  605. 'g',
  606. false,
  607. ToolBarConfigItems.Gradient | ToolBarConfigItems.AlphaBlending)
  608. {
  609. }
  610. }
  611. }