PageRenderTime 57ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/MainForm.cs

https://bitbucket.org/tcz001/openpdn
C# | 1334 lines | 1048 code | 212 blank | 74 comment | 177 complexity | 6cc722d9bb955b107958493113e6dc1a MD5 | raw file
Possible License(s): Unlicense
  1. /////////////////////////////////////////////////////////////////////////////////
  2. // Paint.NET //
  3. // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. //
  4. // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
  5. // See src/Resources/Files/License.txt for full licensing and attribution //
  6. // details. //
  7. // . //
  8. /////////////////////////////////////////////////////////////////////////////////
  9. using PaintDotNet.Actions;
  10. using PaintDotNet.Effects;
  11. using PaintDotNet.Menus;
  12. using PaintDotNet.SystemLayer;
  13. using PaintDotNet.Tools;
  14. using System;
  15. using System.Collections;
  16. using System.Collections.Generic;
  17. using System.Collections.Specialized;
  18. using System.ComponentModel;
  19. using System.Diagnostics;
  20. using System.Drawing;
  21. using System.Drawing.Drawing2D;
  22. using System.Drawing.Imaging;
  23. using System.Globalization;
  24. using System.IO;
  25. using System.Net;
  26. using System.Reflection;
  27. using System.Resources;
  28. using System.Runtime.InteropServices;
  29. using System.Runtime.Serialization;
  30. using System.Security;
  31. using System.Text;
  32. using System.Threading;
  33. using System.Windows.Forms;
  34. namespace PaintDotNet
  35. {
  36. internal sealed class MainForm
  37. : PdnBaseForm
  38. {
  39. private AppWorkspace appWorkspace;
  40. private Button defaultButton;
  41. private FloatingToolForm[] floaters;
  42. private System.Windows.Forms.Timer floaterOpacityTimer;
  43. private System.Windows.Forms.Timer deferredInitializationTimer;
  44. private System.ComponentModel.IContainer components;
  45. private bool killAfterInit = false;
  46. private SplashForm splashForm = null;
  47. private SingleInstanceManager singleInstanceManager = null;
  48. private List<string> queuedInstanceMessages = new List<string>();
  49. public SingleInstanceManager SingleInstanceManager
  50. {
  51. get
  52. {
  53. return this.singleInstanceManager;
  54. }
  55. set
  56. {
  57. if (this.singleInstanceManager != null)
  58. {
  59. this.singleInstanceManager.InstanceMessageReceived -= new EventHandler(SingleInstanceManager_InstanceMessageReceived);
  60. this.singleInstanceManager.SetWindow(null);
  61. }
  62. this.singleInstanceManager = value;
  63. if (this.singleInstanceManager != null)
  64. {
  65. this.singleInstanceManager.SetWindow(this);
  66. this.singleInstanceManager.InstanceMessageReceived += new EventHandler(SingleInstanceManager_InstanceMessageReceived);
  67. }
  68. }
  69. }
  70. private void SingleInstanceManager_InstanceMessageReceived(object sender, EventArgs e)
  71. {
  72. BeginInvoke(new Procedure(ProcessQueuedInstanceMessages), null);
  73. }
  74. public MainForm()
  75. : this(new string[0])
  76. {
  77. }
  78. protected override void WndProc(ref Message m)
  79. {
  80. if (this.singleInstanceManager != null)
  81. {
  82. this.singleInstanceManager.FilterMessage(ref m);
  83. }
  84. base.WndProc(ref m);
  85. }
  86. private enum ArgumentAction
  87. {
  88. Open,
  89. OpenUntitled,
  90. Print,
  91. NoOp
  92. }
  93. private bool SplitMessage(string message, out ArgumentAction action, out string actionParm)
  94. {
  95. if (message.Length == 0)
  96. {
  97. action = ArgumentAction.NoOp;
  98. actionParm = null;
  99. return false;
  100. }
  101. const string printPrefix = "print:";
  102. if (message.IndexOf(printPrefix) == 0)
  103. {
  104. action = ArgumentAction.Print;
  105. actionParm = message.Substring(printPrefix.Length);
  106. return true;
  107. }
  108. const string untitledPrefix = "untitled:";
  109. if (message.IndexOf(untitledPrefix) == 0)
  110. {
  111. action = ArgumentAction.OpenUntitled;
  112. actionParm = message.Substring(untitledPrefix.Length);
  113. return true;
  114. }
  115. action = ArgumentAction.Open;
  116. actionParm = message;
  117. return true;
  118. }
  119. private bool ProcessMessage(string message)
  120. {
  121. if (IsDisposed)
  122. {
  123. return false;
  124. }
  125. ArgumentAction action;
  126. string actionParm;
  127. bool result;
  128. result = SplitMessage(message, out action, out actionParm);
  129. if (!result)
  130. {
  131. return true;
  132. }
  133. switch (action)
  134. {
  135. case ArgumentAction.NoOp:
  136. result = true;
  137. break;
  138. case ArgumentAction.Open:
  139. Activate();
  140. if (IsCurrentModalForm && Enabled)
  141. {
  142. result = this.appWorkspace.OpenFileInNewWorkspace(actionParm);
  143. }
  144. break;
  145. case ArgumentAction.OpenUntitled:
  146. Activate();
  147. if (!string.IsNullOrEmpty(actionParm) && IsCurrentModalForm && Enabled)
  148. {
  149. result = this.appWorkspace.OpenFileInNewWorkspace(actionParm, false);
  150. if (result)
  151. {
  152. this.appWorkspace.ActiveDocumentWorkspace.SetDocumentSaveOptions(null, null, null);
  153. this.appWorkspace.ActiveDocumentWorkspace.Document.Dirty = true;
  154. }
  155. }
  156. break;
  157. case ArgumentAction.Print:
  158. Activate();
  159. if (!string.IsNullOrEmpty(actionParm) && IsCurrentModalForm && Enabled)
  160. {
  161. result = this.appWorkspace.OpenFileInNewWorkspace(actionParm);
  162. if (result)
  163. {
  164. DocumentWorkspace dw = this.appWorkspace.ActiveDocumentWorkspace;
  165. PrintAction pa = new PrintAction();
  166. dw.PerformAction(pa);
  167. CloseWorkspaceAction cwa = new CloseWorkspaceAction(dw);
  168. this.appWorkspace.PerformAction(cwa);
  169. if (this.appWorkspace.DocumentWorkspaces.Length == 0)
  170. {
  171. Startup.CloseApplication();
  172. }
  173. }
  174. }
  175. break;
  176. default:
  177. throw new InvalidEnumArgumentException();
  178. }
  179. return result;
  180. }
  181. private void ProcessQueuedInstanceMessages()
  182. {
  183. if (IsDisposed)
  184. {
  185. return;
  186. }
  187. if (this.splashForm != null)
  188. {
  189. this.splashForm.Close();
  190. this.splashForm.Dispose();
  191. this.splashForm = null;
  192. }
  193. if (IsHandleCreated &&
  194. !PdnInfo.IsExpired &&
  195. this.singleInstanceManager != null)
  196. {
  197. string[] messages1 = this.singleInstanceManager.GetPendingInstanceMessages();
  198. string[] messages2 = this.queuedInstanceMessages.ToArray();
  199. this.queuedInstanceMessages.Clear();
  200. string[] messages = new string[messages1.Length + messages2.Length];
  201. for (int i = 0; i < messages1.Length; ++i)
  202. {
  203. messages[i] = messages1[i];
  204. }
  205. for (int i = 0; i < messages2.Length; ++i)
  206. {
  207. messages[i + messages1.Length] = messages2[i];
  208. }
  209. foreach (string message in messages)
  210. {
  211. bool result = ProcessMessage(message);
  212. if (!result)
  213. {
  214. break;
  215. }
  216. }
  217. }
  218. }
  219. private void Application_Idle(object sender, EventArgs e)
  220. {
  221. if (!this.IsDisposed &&
  222. (this.queuedInstanceMessages.Count > 0 || (this.singleInstanceManager != null && this.singleInstanceManager.AreMessagesPending)))
  223. {
  224. ProcessQueuedInstanceMessages();
  225. }
  226. }
  227. public MainForm(string[] args)
  228. {
  229. bool canSetCurrentDir = true;
  230. this.StartPosition = FormStartPosition.WindowsDefaultLocation;
  231. bool splash = false;
  232. List<string> fileNames = new List<string>();
  233. // Parse command line arguments
  234. foreach (string argument in args)
  235. {
  236. if (0 == string.Compare(argument, "/dontForceGC"))
  237. {
  238. Utility.AllowGCFullCollect = false;
  239. }
  240. else if (0 == string.Compare(argument, "/splash", true))
  241. {
  242. splash = true;
  243. }
  244. else if (0 == string.Compare(argument, "/test", true))
  245. {
  246. // This lets us use an alternate update manifest on the web server so that
  247. // we can test manifests on a small scale before "deploying" them to everybody
  248. PdnInfo.IsTestMode = true;
  249. }
  250. else if (0 == string.Compare(argument, "/profileStartupTimed", true))
  251. {
  252. // profileStartupTimed and profileStartupWorkingSet compete, which
  253. // ever is last in the args list wins.
  254. PdnInfo.StartupTest = StartupTestType.Timed;
  255. }
  256. else if (0 == string.Compare(argument, "/profileStartupWorkingSet", true))
  257. {
  258. // profileStartupTimed and profileStartupWorkingSet compete, which
  259. // ever is last in the args list wins.
  260. PdnInfo.StartupTest = StartupTestType.WorkingSet;
  261. }
  262. else if (argument.Length > 0 && argument[0] != '/')
  263. {
  264. try
  265. {
  266. string fullPath = Path.GetFullPath(argument);
  267. fileNames.Add(fullPath);
  268. }
  269. catch (Exception)
  270. {
  271. fileNames.Add(argument);
  272. canSetCurrentDir = false;
  273. }
  274. splash = true;
  275. }
  276. }
  277. if (canSetCurrentDir)
  278. {
  279. try
  280. {
  281. Environment.CurrentDirectory = PdnInfo.GetApplicationDir();
  282. }
  283. catch (Exception ex)
  284. {
  285. Tracing.Ping("Exception while trying to set Environment.CurrentDirectory: " + ex.ToString());
  286. }
  287. }
  288. // make splash, if warranted
  289. if (splash)
  290. {
  291. this.splashForm = new SplashForm();
  292. this.splashForm.TopMost = true;
  293. this.splashForm.Show();
  294. this.splashForm.Update();
  295. }
  296. InitializeComponent();
  297. this.Icon = PdnInfo.AppIcon;
  298. // Does not load window location/state
  299. LoadSettings();
  300. foreach (string fileName in fileNames)
  301. {
  302. this.queuedInstanceMessages.Add(fileName);
  303. }
  304. // no file specified? create a blank image
  305. if (fileNames.Count == 0)
  306. {
  307. MeasurementUnit units = Document.DefaultDpuUnit;
  308. double dpu = Document.GetDefaultDpu(units);
  309. Size newSize = this.appWorkspace.GetNewDocumentSize();
  310. this.appWorkspace.CreateBlankDocumentInNewWorkspace(newSize, units, dpu, true);
  311. this.appWorkspace.ActiveDocumentWorkspace.IncrementJustPaintWhite();
  312. this.appWorkspace.ActiveDocumentWorkspace.Document.Dirty = false;
  313. }
  314. LoadWindowState();
  315. deferredInitializationTimer.Enabled = true;
  316. Application.Idle += new EventHandler(Application_Idle);
  317. }
  318. protected override void OnShown(EventArgs e)
  319. {
  320. base.OnShown(e);
  321. if (PdnInfo.IsExpired)
  322. {
  323. foreach (Form form in Application.OpenForms)
  324. {
  325. form.Enabled = false;
  326. }
  327. TaskButton checkForUpdatesTB = new TaskButton(
  328. PdnResources.GetImageResource("Icons.MenuHelpCheckForUpdatesIcon.png").Reference,
  329. PdnResources.GetString("ExpiredTaskDialog.CheckForUpdatesTB.ActionText"),
  330. PdnResources.GetString("ExpiredTaskDialog.CheckForUpdatesTB.ExplanationText"));
  331. TaskButton goToWebSiteTB = new TaskButton(
  332. PdnResources.GetImageResource("Icons.MenuHelpPdnWebsiteIcon.png").Reference,
  333. PdnResources.GetString("ExpiredTaskDialog.GoToWebSiteTB.ActionText"),
  334. PdnResources.GetString("ExpiredTaskDialog.GoToWebSiteTB.ExplanationText"));
  335. TaskButton doNotCheckForUpdatesTB = new TaskButton(
  336. PdnResources.GetImageResource("Icons.CancelIcon.png").Reference,
  337. PdnResources.GetString("ExpiredTaskDialog.DoNotCheckForUpdatesTB.ActionText"),
  338. PdnResources.GetString("ExpiredTaskDialog.DoNotCheckForUpdatesTB.ExplanationText"));
  339. TaskButton[] taskButtons =
  340. new TaskButton[]
  341. {
  342. checkForUpdatesTB,
  343. goToWebSiteTB,
  344. doNotCheckForUpdatesTB
  345. };
  346. TaskButton clickedTB = TaskDialog.Show(
  347. this,
  348. Icon,
  349. PdnInfo.GetFullAppName(),
  350. PdnResources.GetImageResource("Icons.WarningIcon.png").Reference,
  351. true,
  352. PdnResources.GetString("ExpiredTaskDialog.InfoText"),
  353. taskButtons,
  354. checkForUpdatesTB,
  355. doNotCheckForUpdatesTB,
  356. 450);
  357. if (clickedTB == checkForUpdatesTB)
  358. {
  359. this.appWorkspace.CheckForUpdates();
  360. }
  361. else if (clickedTB == goToWebSiteTB)
  362. {
  363. PdnInfo.LaunchWebSite(this, InvariantStrings.ExpiredPage);
  364. }
  365. Close();
  366. }
  367. }
  368. private void LoadWindowState()
  369. {
  370. try
  371. {
  372. FormWindowState fws = (FormWindowState)Enum.Parse(typeof(FormWindowState),
  373. Settings.CurrentUser.GetString(SettingNames.WindowState, WindowState.ToString()), true);
  374. // if the state was saved as 'minimized' then just ignore whatever was saved
  375. if (fws != FormWindowState.Minimized)
  376. {
  377. if (fws != FormWindowState.Maximized)
  378. {
  379. Rectangle newBounds = Rectangle.Empty;
  380. // Load the registry values into a rectangle so that we
  381. // can update the settings all at once, instead of one
  382. // at a time. This will make loading the size an all or
  383. // none operation, with no rollback necessary
  384. newBounds.Width = Settings.CurrentUser.GetInt32(SettingNames.Width, this.Width);
  385. newBounds.Height = Settings.CurrentUser.GetInt32(SettingNames.Height, this.Height);
  386. int left = Settings.CurrentUser.GetInt32(SettingNames.Left, this.Left);
  387. int top = Settings.CurrentUser.GetInt32(SettingNames.Top, this.Top);
  388. newBounds.Location = new Point(left, top);
  389. this.Bounds = newBounds;
  390. }
  391. this.WindowState = fws;
  392. }
  393. }
  394. catch
  395. {
  396. try
  397. {
  398. Settings.CurrentUser.Delete(
  399. new string[]
  400. {
  401. SettingNames.Width,
  402. SettingNames.Height,
  403. SettingNames.WindowState,
  404. SettingNames.Top,
  405. SettingNames.Left
  406. });
  407. }
  408. catch
  409. {
  410. // ignore errors
  411. }
  412. }
  413. }
  414. private void LoadSettings()
  415. {
  416. try
  417. {
  418. PdnBaseForm.EnableOpacity = Settings.CurrentUser.GetBoolean(SettingNames.TranslucentWindows, true);
  419. }
  420. catch (Exception ex)
  421. {
  422. Tracing.Ping("Exception in MainForm.LoadSettings:" + ex.ToString());
  423. try
  424. {
  425. Settings.CurrentUser.Delete(
  426. new string[]
  427. {
  428. SettingNames.TranslucentWindows
  429. });
  430. }
  431. catch
  432. {
  433. }
  434. }
  435. }
  436. private void SaveSettings()
  437. {
  438. Settings.CurrentUser.SetInt32(SettingNames.Width, this.Width);
  439. Settings.CurrentUser.SetInt32(SettingNames.Height, this.Height);
  440. Settings.CurrentUser.SetInt32(SettingNames.Top, this.Top);
  441. Settings.CurrentUser.SetInt32(SettingNames.Left, this.Left);
  442. Settings.CurrentUser.SetString(SettingNames.WindowState, this.WindowState.ToString());
  443. Settings.CurrentUser.SetBoolean(SettingNames.TranslucentWindows, PdnBaseForm.EnableOpacity);
  444. if (this.WindowState != FormWindowState.Minimized)
  445. {
  446. Settings.CurrentUser.SetBoolean(SettingNames.ToolsFormVisible, this.appWorkspace.Widgets.ToolsForm.Visible);
  447. Settings.CurrentUser.SetBoolean(SettingNames.ColorsFormVisible, this.appWorkspace.Widgets.ColorsForm.Visible);
  448. Settings.CurrentUser.SetBoolean(SettingNames.HistoryFormVisible, this.appWorkspace.Widgets.HistoryForm.Visible);
  449. Settings.CurrentUser.SetBoolean(SettingNames.LayersFormVisible, this.appWorkspace.Widgets.LayerForm.Visible);
  450. }
  451. SnapManager.Save(Settings.CurrentUser);
  452. this.appWorkspace.SaveSettings();
  453. }
  454. protected override void OnQueryEndSession(CancelEventArgs e)
  455. {
  456. if (IsCurrentModalForm)
  457. {
  458. OnClosing(e);
  459. }
  460. else
  461. {
  462. foreach (Form form in Application.OpenForms)
  463. {
  464. PdnBaseForm asPDF = form as PdnBaseForm;
  465. if (asPDF != null)
  466. {
  467. asPDF.Flash();
  468. }
  469. }
  470. e.Cancel = true;
  471. }
  472. base.OnQueryEndSession(e);
  473. }
  474. protected override void OnClosing(CancelEventArgs e)
  475. {
  476. if (!e.Cancel)
  477. {
  478. if (this.appWorkspace != null)
  479. {
  480. CloseAllWorkspacesAction cawa = new CloseAllWorkspacesAction();
  481. this.appWorkspace.PerformAction(cawa);
  482. e.Cancel = cawa.Cancelled;
  483. }
  484. }
  485. if (!e.Cancel)
  486. {
  487. SaveSettings();
  488. if (this.floaters != null)
  489. {
  490. foreach (Form hideMe in this.floaters)
  491. {
  492. hideMe.Hide();
  493. }
  494. }
  495. this.Hide();
  496. if (this.queuedInstanceMessages != null)
  497. {
  498. this.queuedInstanceMessages.Clear();
  499. }
  500. SingleInstanceManager sim2 = this.singleInstanceManager;
  501. SingleInstanceManager = null;
  502. if (sim2 != null)
  503. {
  504. sim2.Dispose();
  505. sim2 = null;
  506. }
  507. }
  508. base.OnClosing(e);
  509. }
  510. protected override void OnClosed(EventArgs e)
  511. {
  512. if (this.appWorkspace.ActiveDocumentWorkspace != null)
  513. {
  514. appWorkspace.ActiveDocumentWorkspace.SetTool(null);
  515. }
  516. base.OnClosed(e);
  517. }
  518. /// <summary>
  519. /// Clean up any resources being used.
  520. /// </summary>
  521. protected override void Dispose(bool disposing)
  522. {
  523. if (disposing)
  524. {
  525. if (this.singleInstanceManager != null)
  526. {
  527. SingleInstanceManager sim2 = this.singleInstanceManager;
  528. SingleInstanceManager = null;
  529. sim2.Dispose();
  530. sim2 = null;
  531. }
  532. if (this.floaterOpacityTimer != null)
  533. {
  534. this.floaterOpacityTimer.Tick -= new System.EventHandler(this.FloaterOpacityTimer_Tick);
  535. this.floaterOpacityTimer.Dispose();
  536. this.floaterOpacityTimer = null;
  537. }
  538. if (this.components != null)
  539. {
  540. this.components.Dispose();
  541. this.components = null;
  542. }
  543. }
  544. try
  545. {
  546. base.Dispose(disposing);
  547. }
  548. catch (RankException)
  549. {
  550. // System.Windows.Forms.PropertyStore
  551. // Discard error - bug #2746
  552. }
  553. }
  554. /// <summary>
  555. /// Required method for Designer support - do not modify
  556. /// the contents of this method with the code editor.
  557. /// </summary>
  558. private void InitializeComponent()
  559. {
  560. this.components = new System.ComponentModel.Container();
  561. this.defaultButton = new System.Windows.Forms.Button();
  562. this.appWorkspace = new PaintDotNet.AppWorkspace();
  563. this.floaterOpacityTimer = new System.Windows.Forms.Timer(this.components);
  564. this.deferredInitializationTimer = new System.Windows.Forms.Timer(this.components);
  565. this.SuspendLayout();
  566. //
  567. // appWorkspace
  568. //
  569. this.appWorkspace.Dock = System.Windows.Forms.DockStyle.Fill;
  570. this.appWorkspace.Location = new System.Drawing.Point(0, 0);
  571. this.appWorkspace.Name = "appWorkspace";
  572. this.appWorkspace.Size = new System.Drawing.Size(752, 648);
  573. this.appWorkspace.TabIndex = 2;
  574. this.appWorkspace.ActiveDocumentWorkspaceChanging += new EventHandler(AppWorkspace_ActiveDocumentWorkspaceChanging);
  575. this.appWorkspace.ActiveDocumentWorkspaceChanged += new EventHandler(AppWorkspace_ActiveDocumentWorkspaceChanged);
  576. //
  577. // floaterOpacityTimer
  578. //
  579. this.floaterOpacityTimer.Enabled = false;
  580. this.floaterOpacityTimer.Interval = 25;
  581. this.floaterOpacityTimer.Tick += new System.EventHandler(this.FloaterOpacityTimer_Tick);
  582. //
  583. // deferredInitializationTimer
  584. //
  585. this.deferredInitializationTimer.Interval = 250;
  586. this.deferredInitializationTimer.Tick += new EventHandler(DeferredInitialization);
  587. //
  588. // defaultButton
  589. //
  590. this.defaultButton.Size = new System.Drawing.Size(1, 1);
  591. this.defaultButton.Text = "";
  592. this.defaultButton.Location = new Point(-100, -100);
  593. this.defaultButton.TabStop = false;
  594. this.defaultButton.Click += new EventHandler(DefaultButton_Click);
  595. //
  596. // MainForm
  597. //
  598. try
  599. {
  600. this.AllowDrop = true;
  601. }
  602. catch (InvalidOperationException)
  603. {
  604. // Discard error. See bug #2605.
  605. }
  606. this.AutoScaleDimensions = new SizeF(96F, 96F);
  607. this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
  608. this.ClientSize = new System.Drawing.Size(950, 738);
  609. this.Controls.Add(this.appWorkspace);
  610. this.Controls.Add(this.defaultButton);
  611. this.AcceptButton = this.defaultButton;
  612. this.Name = "MainForm";
  613. this.StartPosition = System.Windows.Forms.FormStartPosition.WindowsDefaultLocation;
  614. this.ForceActiveTitleBar = true;
  615. this.KeyPreview = true;
  616. this.Controls.SetChildIndex(this.appWorkspace, 0);
  617. this.ResumeLayout(false);
  618. this.PerformLayout();
  619. }
  620. private void AppWorkspace_ActiveDocumentWorkspaceChanging(object sender, EventArgs e)
  621. {
  622. if (this.appWorkspace.ActiveDocumentWorkspace != null)
  623. {
  624. this.appWorkspace.ActiveDocumentWorkspace.ScaleFactorChanged -= DocumentWorkspace_ScaleFactorChanged;
  625. this.appWorkspace.ActiveDocumentWorkspace.DocumentChanged -= DocumentWorkspace_DocumentChanged;
  626. this.appWorkspace.ActiveDocumentWorkspace.SaveOptionsChanged -= DocumentWorkspace_SaveOptionsChanged;
  627. }
  628. }
  629. private void AppWorkspace_ActiveDocumentWorkspaceChanged(object sender, EventArgs e)
  630. {
  631. if (this.appWorkspace.ActiveDocumentWorkspace != null)
  632. {
  633. this.appWorkspace.ActiveDocumentWorkspace.ScaleFactorChanged += DocumentWorkspace_ScaleFactorChanged;
  634. this.appWorkspace.ActiveDocumentWorkspace.DocumentChanged += DocumentWorkspace_DocumentChanged;
  635. this.appWorkspace.ActiveDocumentWorkspace.SaveOptionsChanged += DocumentWorkspace_SaveOptionsChanged;
  636. }
  637. SetTitleText();
  638. }
  639. private void DocumentWorkspace_SaveOptionsChanged(object sender, EventArgs e)
  640. {
  641. SetTitleText();
  642. }
  643. private Keys CharToKeys(char c)
  644. {
  645. Keys keys = Keys.None;
  646. c = Char.ToLower(c);
  647. if (c >= 'a' && c <= 'z')
  648. {
  649. keys = (Keys)((int)Keys.A + (int)c - (int)'a');
  650. }
  651. return keys;
  652. }
  653. private Keys GetMenuCmdKey(string text)
  654. {
  655. Keys keys = Keys.None;
  656. for (int i = 0; i < text.Length - 1; ++i)
  657. {
  658. if (text[i] == '&')
  659. {
  660. keys = Keys.Alt | CharToKeys(text[i + 1]);
  661. break;
  662. }
  663. }
  664. return keys;
  665. }
  666. protected override void OnLoad(EventArgs e)
  667. {
  668. EnsureFormIsOnScreen();
  669. if (killAfterInit)
  670. {
  671. Application.Exit();
  672. }
  673. this.floaters = new FloatingToolForm[] {
  674. appWorkspace.Widgets.ToolsForm,
  675. appWorkspace.Widgets.ColorsForm,
  676. appWorkspace.Widgets.HistoryForm,
  677. appWorkspace.Widgets.LayerForm
  678. };
  679. foreach (FloatingToolForm ftf in floaters)
  680. {
  681. ftf.Closing += this.HideInsteadOfCloseHandler;
  682. }
  683. PositionFloatingForms();
  684. base.OnLoad(e);
  685. switch (PdnInfo.StartupTest)
  686. {
  687. case StartupTestType.Timed:
  688. Application.DoEvents();
  689. Application.Exit();
  690. break;
  691. case StartupTestType.WorkingSet:
  692. const int waitPeriodForVadumpSnapshot = 20000;
  693. Application.DoEvents();
  694. Thread.Sleep(waitPeriodForVadumpSnapshot);
  695. Application.Exit();
  696. break;
  697. }
  698. }
  699. private void PositionFloatingForms()
  700. {
  701. this.appWorkspace.ResetFloatingForms();
  702. try
  703. {
  704. SnapManager.Load(Settings.CurrentUser);
  705. }
  706. catch
  707. {
  708. this.appWorkspace.ResetFloatingForms();
  709. }
  710. foreach (FloatingToolForm ftf in floaters)
  711. {
  712. this.AddOwnedForm(ftf);
  713. }
  714. if (Settings.CurrentUser.GetBoolean(SettingNames.ToolsFormVisible, true))
  715. {
  716. this.appWorkspace.Widgets.ToolsForm.Show();
  717. }
  718. if (Settings.CurrentUser.GetBoolean(SettingNames.ColorsFormVisible, true))
  719. {
  720. this.appWorkspace.Widgets.ColorsForm.Show();
  721. }
  722. if (Settings.CurrentUser.GetBoolean(SettingNames.HistoryFormVisible, true))
  723. {
  724. this.appWorkspace.Widgets.HistoryForm.Show();
  725. }
  726. if (Settings.CurrentUser.GetBoolean(SettingNames.LayersFormVisible, true))
  727. {
  728. this.appWorkspace.Widgets.LayerForm.Show();
  729. }
  730. // If the floating form is off screen somehow, reset it
  731. // We've been getting a lot of reports where people say their Colors window has disappeared
  732. Screen[] allScreens = Screen.AllScreens;
  733. foreach (FloatingToolForm ftf in this.floaters)
  734. {
  735. if (!ftf.Visible)
  736. {
  737. continue;
  738. }
  739. bool reset = false;
  740. try
  741. {
  742. bool foundAScreen = false;
  743. foreach (Screen screen in allScreens)
  744. {
  745. Rectangle intersect = Rectangle.Intersect(screen.Bounds, ftf.Bounds);
  746. if (intersect.Width > 0 && intersect.Height > 0)
  747. {
  748. foundAScreen = true;
  749. break;
  750. }
  751. }
  752. if (!foundAScreen)
  753. {
  754. reset = true;
  755. }
  756. }
  757. catch (Exception)
  758. {
  759. reset = true;
  760. }
  761. if (reset)
  762. {
  763. this.appWorkspace.ResetFloatingForm(ftf);
  764. }
  765. }
  766. this.floaterOpacityTimer.Enabled = true;
  767. }
  768. protected override void OnResize(EventArgs e)
  769. {
  770. if (floaterOpacityTimer != null)
  771. {
  772. if (WindowState == FormWindowState.Minimized)
  773. {
  774. if (this.floaterOpacityTimer.Enabled)
  775. {
  776. this.floaterOpacityTimer.Enabled = false;
  777. }
  778. }
  779. else
  780. {
  781. if (!this.floaterOpacityTimer.Enabled)
  782. {
  783. this.floaterOpacityTimer.Enabled = true;
  784. }
  785. this.FloaterOpacityTimer_Tick(this, EventArgs.Empty);
  786. }
  787. }
  788. base.OnResize (e);
  789. }
  790. private void DocumentWorkspace_DocumentChanged(object sender, System.EventArgs e)
  791. {
  792. SetTitleText();
  793. OnResize(EventArgs.Empty);
  794. }
  795. private void SetTitleText()
  796. {
  797. if (this.appWorkspace == null)
  798. {
  799. return;
  800. }
  801. if (this.appWorkspace.ActiveDocumentWorkspace == null)
  802. {
  803. this.Text = PdnInfo.GetAppName();
  804. }
  805. else
  806. {
  807. string appTitle = PdnInfo.GetAppName();
  808. string ratio = string.Empty;
  809. string title = string.Empty;
  810. string friendlyName = this.appWorkspace.ActiveDocumentWorkspace.GetFriendlyName();
  811. string text;
  812. if (this.WindowState != FormWindowState.Minimized)
  813. {
  814. string format = PdnResources.GetString("MainForm.Title.Format.Normal");
  815. text = string.Format(format, friendlyName, appWorkspace.ActiveDocumentWorkspace.ScaleFactor, appTitle);
  816. }
  817. else
  818. {
  819. string format = PdnResources.GetString("MainForm.Title.Format.Minimized");
  820. text = string.Format(format, friendlyName, appTitle);
  821. }
  822. if (appWorkspace.ActiveDocumentWorkspace.Document != null)
  823. {
  824. title = text;
  825. }
  826. this.Text = title;
  827. }
  828. }
  829. // For the menus where we dynamically enable menu items (e.g. Copy only enabled when there's a selection),
  830. // we have to make sure to re-enable all the items when the menu goes way.
  831. // This is important for cases where, for example: Edit menu is opened, "Deselect" is disabled because
  832. // there is no selection. User then clicks on Select All. The menu then goes away. However, since Deselect
  833. // was disabled, the Ctrl+D shortcut will not be honored even though there is a selection.
  834. // So the disabling of menu items should only be temporary for the duration of the menu's visibility.
  835. private void OnMenuDropDownClosed(object sender, System.EventArgs e)
  836. {
  837. ToolStripMenuItem menu = (ToolStripMenuItem)sender;
  838. foreach (ToolStripItem tsi in menu.DropDownItems)
  839. {
  840. tsi.Enabled = true;
  841. }
  842. }
  843. private void HideInsteadOfCloseHandler(object sender, CancelEventArgs e)
  844. {
  845. e.Cancel = true;
  846. ((Form)sender).Hide();
  847. }
  848. // TODO: refactor into FloatingToolForm class somehow
  849. private void FloaterOpacityTimer_Tick(object sender, System.EventArgs e)
  850. {
  851. if (this.WindowState == FormWindowState.Minimized ||
  852. this.floaters == null ||
  853. !PdnBaseForm.EnableOpacity ||
  854. this.appWorkspace.ActiveDocumentWorkspace == null)
  855. {
  856. return;
  857. }
  858. // Here's the behavior we want for our floaters:
  859. // 1. If the mouse is within a floaters rectangle, it should transition to fully opaque
  860. // 2. If the mouse is outside the floater's rectangle, it should transition to partially
  861. // opaque
  862. // 3. However, if the floater is outside where the document is visible on screen, it
  863. // should always be fully opaque.
  864. Rectangle screenDocRect;
  865. try
  866. {
  867. screenDocRect = this.appWorkspace.ActiveDocumentWorkspace.VisibleDocumentBounds;
  868. }
  869. catch (ObjectDisposedException)
  870. {
  871. return; // do nothing, we are probably in the process of shutting down the app
  872. }
  873. for (int i = 0; i < floaters.Length; ++i)
  874. {
  875. FloatingToolForm ftf = floaters[i];
  876. Rectangle intersect = Rectangle.Intersect(screenDocRect, ftf.Bounds);
  877. double opacity = -1.0;
  878. try
  879. {
  880. if (intersect.Width == 0 ||
  881. intersect.Height == 0 ||
  882. (ftf.Bounds.Contains(Control.MousePosition) &&
  883. !appWorkspace.ActiveDocumentWorkspace.IsMouseCaptured()) ||
  884. Utility.DoesControlHaveMouseCaptured(ftf))
  885. {
  886. opacity = Math.Min(1.0, ftf.Opacity + 0.125);
  887. }
  888. else
  889. {
  890. opacity = Math.Max(0.75, ftf.Opacity - 0.0625);
  891. }
  892. if (opacity != ftf.Opacity)
  893. {
  894. ftf.Opacity = opacity;
  895. }
  896. }
  897. catch (System.ComponentModel.Win32Exception)
  898. {
  899. // We just eat the exception. Chris Strahl was having some problem where opacity was 0.7
  900. // and we were trying to set it to 0.7 and it said "the parameter is incorrect"
  901. // ... which is stupid. Bad NVIDIA drivers for his GeForce Go?
  902. }
  903. }
  904. }
  905. protected override void OnDragEnter(DragEventArgs drgevent)
  906. {
  907. if (Enabled && drgevent.Data.GetDataPresent(DataFormats.FileDrop))
  908. {
  909. string[] files = (string[])drgevent.Data.GetData(DataFormats.FileDrop);
  910. foreach (string file in files)
  911. {
  912. try
  913. {
  914. FileAttributes fa = File.GetAttributes(file);
  915. if ((fa & FileAttributes.Directory) == 0)
  916. {
  917. drgevent.Effect = DragDropEffects.Copy;
  918. }
  919. }
  920. catch
  921. {
  922. }
  923. }
  924. }
  925. base.OnDragEnter(drgevent);
  926. }
  927. private string[] PruneDirectories(string[] fileNames)
  928. {
  929. List<string> result = new List<string>();
  930. foreach (string fileName in fileNames)
  931. {
  932. try
  933. {
  934. FileAttributes fa = File.GetAttributes(fileName);
  935. if ((fa & FileAttributes.Directory) == 0)
  936. {
  937. result.Add(fileName);
  938. }
  939. }
  940. catch
  941. {
  942. }
  943. }
  944. return result.ToArray();
  945. }
  946. protected override void OnDragDrop(DragEventArgs drgevent)
  947. {
  948. Activate();
  949. if (!IsCurrentModalForm || !Enabled)
  950. {
  951. // do nothing
  952. }
  953. else if (drgevent.Data.GetDataPresent(DataFormats.FileDrop))
  954. {
  955. string[] allFiles = (string[])drgevent.Data.GetData(DataFormats.FileDrop);
  956. if (allFiles == null)
  957. {
  958. return;
  959. }
  960. string[] files = PruneDirectories(allFiles);
  961. bool importAsLayers = true;
  962. if (files.Length == 0)
  963. {
  964. return;
  965. }
  966. else
  967. {
  968. Icon formIcon = Utility.ImageToIcon(PdnResources.GetImageResource("Icons.DragDrop.OpenOrImport.FormIcon.png").Reference);
  969. string title = PdnResources.GetString("DragDrop.OpenOrImport.Title");
  970. string infoText = PdnResources.GetString("DragDrop.OpenOrImport.InfoText");
  971. TaskButton openTB = new TaskButton(
  972. PdnResources.GetImageResource("Icons.MenuFileOpenIcon.png").Reference,
  973. PdnResources.GetString("DragDrop.OpenOrImport.OpenButton.ActionText"),
  974. PdnResources.GetString("DragDrop.OpenOrImport.OpenButton.ExplanationText"));
  975. string importLayersExplanation;
  976. if (this.appWorkspace.DocumentWorkspaces.Length == 0)
  977. {
  978. importLayersExplanation = PdnResources.GetString("DragDrop.OpenOrImport.ImportLayers.ExplanationText.NoImagesYet");
  979. }
  980. else
  981. {
  982. importLayersExplanation = PdnResources.GetString("DragDrop.OpenOrImport.ImportLayers.ExplanationText");
  983. }
  984. TaskButton importLayersTB = new TaskButton(
  985. PdnResources.GetImageResource("Icons.MenuLayersImportFromFileIcon.png").Reference,
  986. PdnResources.GetString("DragDrop.OpenOrImport.ImportLayers.ActionText"),
  987. importLayersExplanation);
  988. TaskButton clickedTB = TaskDialog.Show(
  989. this,
  990. formIcon,
  991. title,
  992. null,
  993. false,
  994. infoText,
  995. new TaskButton[] { openTB, importLayersTB, TaskButton.Cancel },
  996. null,
  997. TaskButton.Cancel);
  998. if (clickedTB == openTB)
  999. {
  1000. importAsLayers = false;
  1001. }
  1002. else if (clickedTB == importLayersTB)
  1003. {
  1004. importAsLayers = true;
  1005. }
  1006. else
  1007. {
  1008. return;
  1009. }
  1010. }
  1011. if (!importAsLayers)
  1012. {
  1013. // open files into new tabs
  1014. this.appWorkspace.OpenFilesInNewWorkspace(files);
  1015. }
  1016. else
  1017. {
  1018. // no image open? we will have to create one
  1019. if (this.appWorkspace.ActiveDocumentWorkspace == null)
  1020. {
  1021. Size newSize = this.appWorkspace.GetNewDocumentSize();
  1022. this.appWorkspace.CreateBlankDocumentInNewWorkspace(
  1023. newSize,
  1024. Document.DefaultDpuUnit,
  1025. Document.GetDefaultDpu(Document.DefaultDpuUnit),
  1026. false);
  1027. }
  1028. ImportFromFileAction action = new ImportFromFileAction();
  1029. HistoryMemento ha = action.ImportMultipleFiles(this.appWorkspace.ActiveDocumentWorkspace, files);
  1030. if (ha != null)
  1031. {
  1032. this.appWorkspace.ActiveDocumentWorkspace.History.PushNewMemento(ha);
  1033. }
  1034. }
  1035. }
  1036. base.OnDragDrop(drgevent);
  1037. }
  1038. private void DocumentWorkspace_ScaleFactorChanged(object sender, EventArgs e)
  1039. {
  1040. SetTitleText();
  1041. }
  1042. protected override void OnSizeChanged(EventArgs e)
  1043. {
  1044. base.OnSizeChanged(e);
  1045. SetTitleText();
  1046. }
  1047. private void DeferredInitialization(object sender, EventArgs e)
  1048. {
  1049. this.deferredInitializationTimer.Enabled = false;
  1050. this.deferredInitializationTimer.Tick -= new EventHandler(DeferredInitialization);
  1051. this.deferredInitializationTimer.Dispose();
  1052. this.deferredInitializationTimer = null;
  1053. // TODO
  1054. this.appWorkspace.ToolBar.MainMenu.PopulateEffects();
  1055. }
  1056. protected override void OnHelpRequested(HelpEventArgs hevent)
  1057. {
  1058. // F1 is already handled by the Menu->Help menu item. No need to process it twice.
  1059. hevent.Handled = true;
  1060. base.OnHelpRequested(hevent);
  1061. }
  1062. private void DefaultButton_Click(object sender, EventArgs e)
  1063. {
  1064. // Since defaultButton is the AcceptButton, hitting Enter will get 'eaten' by this button
  1065. // So we have to give the Enter key to the Tool
  1066. if (this.appWorkspace.ActiveDocumentWorkspace != null)
  1067. {
  1068. this.appWorkspace.ActiveDocumentWorkspace.Focus();
  1069. if (this.appWorkspace.ActiveDocumentWorkspace.Tool != null)
  1070. {
  1071. this.appWorkspace.ActiveDocumentWorkspace.Tool.PerformKeyPress(new KeyPressEventArgs('\r'));
  1072. this.appWorkspace.ActiveDocumentWorkspace.Tool.PerformKeyPress(Keys.Enter);
  1073. }
  1074. }
  1075. }
  1076. #if DEBUG
  1077. static MainForm()
  1078. {
  1079. new Thread(FocusPrintThread).Start();
  1080. }
  1081. private static string GetControlName(Control control)
  1082. {
  1083. if (control == null)
  1084. {
  1085. return "null";
  1086. }
  1087. string name = control.Name + "(" + control.GetType().Name + ")";
  1088. if (control.Parent != null)
  1089. {
  1090. name += " <- " + GetControlName(control.Parent);
  1091. }
  1092. return name;
  1093. }
  1094. private static void PrintFocus()
  1095. {
  1096. Control c = Utility.FindFocus();
  1097. Tracing.Ping("Focused: " + GetControlName(c));
  1098. }
  1099. private static void FocusPrintThread()
  1100. {
  1101. Thread.CurrentThread.IsBackground = true;
  1102. while (true)
  1103. {
  1104. try
  1105. {
  1106. FormCollection forms = Application.OpenForms;
  1107. Form form;
  1108. if (forms.Count > 0)
  1109. {
  1110. form = forms[0];
  1111. form.BeginInvoke(new Procedure(PrintFocus));
  1112. }
  1113. }
  1114. catch
  1115. {
  1116. }
  1117. Thread.Sleep(1000);
  1118. }
  1119. }
  1120. #endif
  1121. }
  1122. }