PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/src/MainForm.cs

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