From a8a93b11ba612e9dfdc1a7c31b70b146bbc90040 Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Fri, 20 May 2016 21:41:58 +0300 Subject: [PATCH] Extreact Thumbnail and Settings management code from main form --- Eve-O-Preview/Configuration/Configuration.cs | 7 + .../Configuration/ConfigurationStorage.cs | 7 + Eve-O-Preview/Eve-O-Preview.csproj | 3 + Eve-O-Preview/GUI/MainForm.cs | 617 ++++-------------- Eve-O-Preview/Thumbnail/ThumbnailFactory.cs | 4 +- Eve-O-Preview/Thumbnail/ThumbnailManager.cs | 507 ++++++++++++++ Eve-O-Preview/Thumbnail/ThumbnailWindow.cs | 14 +- 7 files changed, 644 insertions(+), 515 deletions(-) create mode 100644 Eve-O-Preview/Configuration/Configuration.cs create mode 100644 Eve-O-Preview/Configuration/ConfigurationStorage.cs create mode 100644 Eve-O-Preview/Thumbnail/ThumbnailManager.cs diff --git a/Eve-O-Preview/Configuration/Configuration.cs b/Eve-O-Preview/Configuration/Configuration.cs new file mode 100644 index 0000000..62d40ec --- /dev/null +++ b/Eve-O-Preview/Configuration/Configuration.cs @@ -0,0 +1,7 @@ +namespace EveOPreview +{ + public class Configuration + { + + } +} \ No newline at end of file diff --git a/Eve-O-Preview/Configuration/ConfigurationStorage.cs b/Eve-O-Preview/Configuration/ConfigurationStorage.cs new file mode 100644 index 0000000..974930e --- /dev/null +++ b/Eve-O-Preview/Configuration/ConfigurationStorage.cs @@ -0,0 +1,7 @@ +namespace EveOPreview.Managers +{ + public class ConfigurationStorage + { + + } +} \ No newline at end of file diff --git a/Eve-O-Preview/Eve-O-Preview.csproj b/Eve-O-Preview/Eve-O-Preview.csproj index 9e8f21c..99848fb 100644 --- a/Eve-O-Preview/Eve-O-Preview.csproj +++ b/Eve-O-Preview/Eve-O-Preview.csproj @@ -110,6 +110,7 @@ + @@ -118,8 +119,10 @@ MainForm.cs + + Form diff --git a/Eve-O-Preview/GUI/MainForm.cs b/Eve-O-Preview/GUI/MainForm.cs index 52f7249..902c16a 100644 --- a/Eve-O-Preview/GUI/MainForm.cs +++ b/Eve-O-Preview/GUI/MainForm.cs @@ -12,29 +12,13 @@ namespace EveOPreview { public partial class MainForm : Form { - private readonly ThumbnailFactory _thumbnailFactory; - public event EventHandler Minimized; public event EventHandler Maximized; public event EventHandler Restored; - - private readonly Dictionary _previews; - private DispatcherTimer _dispatcherTimer; - - private IntPtr _activeClientHandle; - private string _activeClientTitle; - - private readonly Dictionary> _uniqueLayouts; - private readonly Dictionary _flatLayout; - private readonly Dictionary _flatLayoutShortcuts; - private readonly Dictionary _clientLayout; - private readonly bool _isInitialized; + private readonly ThumbnailManager _manager; - private readonly Stopwatch _ignoringSizeSync; - - private readonly Dictionary _xmlBadToOkChars; private Dictionary _zoomAnchorButtonMap; @@ -42,49 +26,63 @@ namespace EveOPreview { _isInitialized = false; - this._activeClientHandle = (IntPtr)0; - this._activeClientTitle = ""; - - this._previews = new Dictionary(); - - _xmlBadToOkChars = new Dictionary(); - _xmlBadToOkChars["<"] = "---lt---"; - _xmlBadToOkChars["&"] = "---amp---"; - _xmlBadToOkChars[">"] = "---gt---"; - _xmlBadToOkChars["\""] = "---quot---"; - _xmlBadToOkChars["\'"] = "---apos---"; - _xmlBadToOkChars[","] = "---comma---"; - _xmlBadToOkChars["."] = "---dot---"; - - _uniqueLayouts = new Dictionary>(); - _flatLayout = new Dictionary(); - _flatLayoutShortcuts = new Dictionary(); - _clientLayout = new Dictionary(); - - _ignoringSizeSync = new Stopwatch(); - _ignoringSizeSync.Start(); - InitializeComponent(); init_options(); - // DispatcherTimer setup - _dispatcherTimer = new DispatcherTimer(); - _dispatcherTimer.Tick += dispatcherTimer_Tick; - _dispatcherTimer.Interval = new TimeSpan(0, 0, 1); - _dispatcherTimer.Start(); + // TODO Fix this + previews_check_listbox.DisplayMember = "Text"; - this._thumbnailFactory = new ThumbnailFactory(); + this._manager = new ThumbnailManager(add_thumbnail,remove_thumbnail, set_aero_status, set_size); _isInitialized = true; - previews_check_listbox.DisplayMember = "Text"; - + this._manager.Activate(); } + private void add_thumbnail(IList thumbnails) + { + this.previews_check_listbox.BeginUpdate(); + foreach (string th in thumbnails) + { + previews_check_listbox.Items.Add(th); + } + this.previews_check_listbox.EndUpdate(); + } + + private void remove_thumbnail(IList thumbnails) + { + this.previews_check_listbox.BeginUpdate(); + foreach (string th in thumbnails) + { + previews_check_listbox.Items.Remove(th); + } + this.previews_check_listbox.EndUpdate(); + } + + private void set_aero_status(bool value) + { + + if (value) + { + aero_status_label.Text = "AERO is ON"; + aero_status_label.ForeColor = Color.Black; + } + else + { + aero_status_label.Text = "AERO is OFF"; + aero_status_label.ForeColor = Color.Red; + } + } + + private void set_size(int x, int y) + { + option_sync_size_x.Text = x.ToString(); + option_sync_size_y.Text = y.ToString(); + } private void GlassForm_Load(object sender, EventArgs e) { - refresh_thumbnails(); + this._manager.refresh_thumbnails(); } private void init_options() @@ -131,470 +129,60 @@ namespace EveOPreview } opacity_bar.Value = Math.Min(100, (int)(100.0 * Properties.Settings.Default.opacity)); - - load_layout(); } - private void spawn_and_kill_previews() - { - if (!_isInitialized) { return; } - - Process[] processes = Process.GetProcessesByName("ExeFile"); - List processHandles = new List(); - - // pop new previews - - foreach (Process process in processes) - { - processHandles.Add(process.MainWindowHandle); - - Size sync_size = new Size(); - sync_size.Width = (int)Properties.Settings.Default.sync_resize_x; - sync_size.Height = (int)Properties.Settings.Default.sync_resize_y; - - if (!_previews.ContainsKey(process.MainWindowHandle) && process.MainWindowTitle != "") - { - _previews[process.MainWindowHandle] = this._thumbnailFactory.Create(this, process.MainWindowHandle, "...", sync_size); - - // apply more thumbnail specific options - _previews[process.MainWindowHandle].SetTopMost(Properties.Settings.Default.always_on_top); - _previews[process.MainWindowHandle].SetWindowFrames(Properties.Settings.Default.show_thumb_frames); - - // add a preview also - previews_check_listbox.BeginUpdate(); - previews_check_listbox.Items.Add(_previews[process.MainWindowHandle]); - previews_check_listbox.EndUpdate(); - - refresh_client_window_locations(process); - } - - else if (_previews.ContainsKey(process.MainWindowHandle) && process.MainWindowTitle != _previews[process.MainWindowHandle].GetLabel()) //or update the preview titles - { - _previews[process.MainWindowHandle].SetLabel(process.MainWindowTitle); - string key = _previews[process.MainWindowHandle].GetLabel(); - string value; - if (_flatLayoutShortcuts.TryGetValue(key, out value)) - { - _previews[process.MainWindowHandle].RegisterShortcut(value); - } - refresh_client_window_locations(process); - } - - if (process.MainWindowHandle == DwmApiNativeMethods.GetForegroundWindow()) - { - _activeClientHandle = process.MainWindowHandle; - _activeClientTitle = process.MainWindowTitle; - } - - } - - // clean up old previews - List to_be_pruned = new List(); - foreach (IntPtr processHandle in _previews.Keys) - { - if (!(processHandles.Contains(processHandle))) - { - to_be_pruned.Add(processHandle); - } - } - - foreach (IntPtr processHandle in to_be_pruned) - { - previews_check_listbox.BeginUpdate(); - previews_check_listbox.Items.Remove(_previews[processHandle]); - previews_check_listbox.EndUpdate(); - - _previews[processHandle].CloseThumbnail(); - _previews.Remove(processHandle); - } - - previews_check_listbox.Update(); - - } - - private void refresh_client_window_locations(Process process) - { - if (Properties.Settings.Default.track_client_windows && _clientLayout.ContainsKey(process.MainWindowTitle)) - { - DwmApiNativeMethods.MoveWindow(process.MainWindowHandle, _clientLayout[process.MainWindowTitle].X, - _clientLayout[process.MainWindowTitle].Y, _clientLayout[process.MainWindowTitle].Width, - _clientLayout[process.MainWindowTitle].Height, true); - } - } - - - private string remove_nonconform_xml_characters(string entry) - { - foreach (var kv in _xmlBadToOkChars) - { - entry = entry.Replace(kv.Key, kv.Value); - } - return entry; - } - - private string restore_nonconform_xml_characters(string entry) - { - foreach (var kv in _xmlBadToOkChars) - { - entry = entry.Replace(kv.Value, kv.Key); - } - return entry; - } - - private XElement MakeXElement(string input) - { - string clean = remove_nonconform_xml_characters(input).Replace(" ", "_"); - return new XElement(clean); - } - - private string ParseXElement(XElement input) - { - return restore_nonconform_xml_characters(input.Name.ToString()).Replace("_", " "); - } - - private void load_layout() - { - if (File.Exists("layout.xml")) - { - XElement rootElement = XElement.Load("layout.xml"); - foreach (var el in rootElement.Elements()) - { - Dictionary inner = new Dictionary(); - foreach (var inner_el in el.Elements()) - { - inner[ParseXElement(inner_el)] = new Point(Convert.ToInt32(inner_el.Element("x")?.Value), Convert.ToInt32(inner_el.Element("y")?.Value)); - } - _uniqueLayouts[ParseXElement(el)] = inner; - } - } - - if (File.Exists("flat_layout.xml")) - { - XElement rootElement = XElement.Load("flat_layout.xml"); - foreach (var el in rootElement.Elements()) - { - _flatLayout[ParseXElement(el)] = new Point(Convert.ToInt32(el.Element("x").Value), Convert.ToInt32(el.Element("y").Value)); - _flatLayoutShortcuts[ParseXElement(el)] = ""; - - if (el.Element("shortcut") != null) - { - _flatLayoutShortcuts[ParseXElement(el)] = el.Element("shortcut").Value; - } - } - } - - if (File.Exists("client_layout.xml")) - { - XElement rootElement = XElement.Load("client_layout.xml"); - foreach (var el in rootElement.Elements()) - { - ClientLocation clientLocation = new ClientLocation(); - clientLocation.X = Convert.ToInt32(el.Element("x").Value); - clientLocation.Y = Convert.ToInt32(el.Element("y").Value); - clientLocation.Width = Convert.ToInt32(el.Element("width").Value); - clientLocation.Height = Convert.ToInt32(el.Element("height").Value); - - _clientLayout[ParseXElement(el)] = clientLocation; - } - } - } - - private void store_layout() - { - XElement el = new XElement("layouts"); - foreach (var client in _uniqueLayouts.Keys) - { - if (client == "") - { - continue; - } - XElement layout = MakeXElement(client); - foreach (var thumbnail_ in _uniqueLayouts[client]) - { - string thumbnail = thumbnail_.Key; - if (thumbnail == "" || thumbnail == "...") - { - continue; - } - XElement position = MakeXElement(thumbnail); - position.Add(new XElement("x", thumbnail_.Value.X)); - position.Add(new XElement("y", thumbnail_.Value.Y)); - layout.Add(position); - } - el.Add(layout); - } - - el.Save("layout.xml"); - - XElement el2 = new XElement("flat_layout"); - foreach (var clientKV in _flatLayout) - { - if (clientKV.Key == "" || clientKV.Key == "...") - { - continue; - } - XElement layout = MakeXElement(clientKV.Key); - layout.Add(new XElement("x", clientKV.Value.X)); - layout.Add(new XElement("y", clientKV.Value.Y)); - - string shortcut; - if (_flatLayoutShortcuts.TryGetValue(clientKV.Key, out shortcut)) - { - layout.Add(new XElement("shortcut", shortcut)); - } - el2.Add(layout); - } - - el2.Save("flat_layout.xml"); - - XElement el3 = new XElement("client_layout"); - foreach (var clientKV in _clientLayout) - { - if (clientKV.Key == "" || clientKV.Key == "...") - { - continue; - } - XElement layout = MakeXElement(clientKV.Key); - layout.Add(new XElement("x", clientKV.Value.X)); - layout.Add(new XElement("y", clientKV.Value.Y)); - layout.Add(new XElement("width", clientKV.Value.Width)); - layout.Add(new XElement("height", clientKV.Value.Height)); - el3.Add(layout); - } - - el3.Save("client_layout.xml"); - } - - private void handle_unique_layout(IThumbnail thumbnailWindow, string last_known_active_window) - { - Dictionary layout; - if (_uniqueLayouts.TryGetValue(last_known_active_window, out layout)) - { - Point new_loc; - if (Properties.Settings.Default.unique_layout && layout.TryGetValue(thumbnailWindow.GetLabel(), out new_loc)) - { - thumbnailWindow.SetLocation(new_loc); - } - else - { - // create inner dict - layout[thumbnailWindow.GetLabel()] = thumbnailWindow.GetLocation(); - } - } - else if (last_known_active_window != "") - { - // create outer dict - _uniqueLayouts[last_known_active_window] = new Dictionary(); - _uniqueLayouts[last_known_active_window][thumbnailWindow.GetLabel()] = thumbnailWindow.GetLocation(); - } - } - - - private void update_client_locations() - { - Process[] processes = Process.GetProcessesByName("ExeFile"); - List processHandles = new List(); - - foreach (Process process in processes) - { - RECT rect = new RECT(); - DwmApiNativeMethods.GetWindowRect(process.MainWindowHandle, out rect); - - int left = Math.Abs(rect.Left); - int right = Math.Abs(rect.Right); - int client_width = Math.Abs(left - right); - - int top = Math.Abs(rect.Top); - int bottom = Math.Abs(rect.Bottom); - int client_height = Math.Abs(top - bottom); - - ClientLocation clientLocation = new ClientLocation(); - clientLocation.X = rect.Left; - clientLocation.Y = rect.Top; - clientLocation.Width = client_width; - clientLocation.Height = client_height; - - - _clientLayout[process.MainWindowTitle] = clientLocation; - } - } - - - public void NotifyPreviewSwitch() - { - update_client_locations(); - store_layout(); //todo: check if it actually changed ... - foreach (KeyValuePair entry in _previews) - { - entry.Value.SetTopMost(Properties.Settings.Default.always_on_top); - } - } - - - private void handle_flat_layout(IThumbnail thumbnailWindow) - { - Point layout; - if (_flatLayout.TryGetValue(thumbnailWindow.GetLabel(), out layout)) - { - thumbnailWindow.SetLocation(layout); - } - else if (thumbnailWindow.GetLabel() != "") - { - _flatLayout[thumbnailWindow.GetLabel()] = thumbnailWindow.GetLocation(); - } - } - - private bool window_is_preview_or_client(IntPtr window) - { - bool active_window_is_right_type = false; - foreach (KeyValuePair entry in _previews) - { - if (entry.Key == window || entry.Value.IsPreviewHandle(window)) - { - active_window_is_right_type = true; - } - } - return active_window_is_right_type; - } - - - private void refresh_thumbnails() - { - - IntPtr active_window = DwmApiNativeMethods.GetForegroundWindow(); - - // hide, show, resize and move - foreach (KeyValuePair entry in _previews) - { - if (!window_is_preview_or_client(active_window) && Properties.Settings.Default.hide_all) - { - entry.Value.HideThumbnail(); - } - else if (entry.Key == _activeClientHandle && Properties.Settings.Default.hide_active) - { - entry.Value.HideThumbnail(); - } - else - { - entry.Value.ShowThumbnail(); - if (Properties.Settings.Default.unique_layout) - { - handle_unique_layout(entry.Value, _activeClientTitle); - } - else - { - handle_flat_layout(entry.Value); - } - } - entry.Value.IsZoomEnabled = Properties.Settings.Default.zoom_on_hover; - entry.Value.IsOverlayEnabled = Properties.Settings.Default.show_overlay; - entry.Value.SetOpacity(Properties.Settings.Default.opacity); - } - - DwmApiNativeMethods.DwmIsCompositionEnabled(); - } - - - public void SyncPreviewSize(Size sync_size) - { - if (!_isInitialized) { return; } - - if (Properties.Settings.Default.sync_resize && - Properties.Settings.Default.show_thumb_frames && - _ignoringSizeSync.ElapsedMilliseconds > 500) - { - _ignoringSizeSync.Stop(); - - option_sync_size_x.Text = sync_size.Width.ToString(); - option_sync_size_y.Text = sync_size.Height.ToString(); - - foreach (KeyValuePair entry in _previews) - { - if (entry.Value.IsPreviewHandle(DwmApiNativeMethods.GetForegroundWindow())) - { - entry.Value.SetSize(sync_size); - } - } - - } - - } - - - public void UpdatePreviewPosition(string preview_title, Point position) - { - - if (Properties.Settings.Default.unique_layout) - { - Dictionary layout; - if (_uniqueLayouts.TryGetValue(_activeClientTitle, out layout)) - { - layout[preview_title] = position; - } - else if (_activeClientTitle == "") - { - _uniqueLayouts[_activeClientTitle] = new Dictionary(); - _uniqueLayouts[_activeClientTitle][preview_title] = position; - } - } - else - { - _flatLayout[preview_title] = position; - } - - } - - - private void dispatcherTimer_Tick(object sender, EventArgs e) - { - spawn_and_kill_previews(); - refresh_thumbnails(); - if (_ignoringSizeSync.ElapsedMilliseconds > 500) { _ignoringSizeSync.Stop(); }; - - if (DwmApiNativeMethods.DwmIsCompositionEnabled()) - { - aero_status_label.Text = "AERO is ON"; - aero_status_label.ForeColor = Color.Black; - } - else - { - aero_status_label.Text = "AERO is OFF"; - aero_status_label.ForeColor = Color.Red; - } - - } private void option_hide_all_if_noneve_CheckedChanged(object sender, EventArgs e) { + if (!_isInitialized) + { + return; + } + Properties.Settings.Default.hide_all = option_hide_all_if_not_right_type.Checked; Properties.Settings.Default.Save(); - refresh_thumbnails(); + this._manager.refresh_thumbnails(); } private void option_unique_layout_CheckedChanged(object sender, EventArgs e) { + if (!_isInitialized) + { + return; + } + Properties.Settings.Default.unique_layout = option_unique_layout.Checked; Properties.Settings.Default.Save(); - refresh_thumbnails(); + this._manager.refresh_thumbnails(); } private void option_hide_active_CheckedChanged(object sender, EventArgs e) { + if (!_isInitialized) + { + return; + } + Properties.Settings.Default.hide_active = option_hide_active.Checked; Properties.Settings.Default.Save(); - refresh_thumbnails(); + this._manager.refresh_thumbnails(); } private void option_sync_size_CheckedChanged(object sender, EventArgs e) { + if (!_isInitialized) + { + return; + } + Properties.Settings.Default.sync_resize = option_sync_size.Checked; Properties.Settings.Default.Save(); - refresh_thumbnails(); + this._manager.refresh_thumbnails(); } @@ -622,51 +210,59 @@ namespace EveOPreview Properties.Settings.Default.Save(); // resize - SyncPreviewSize(new Size((int)Properties.Settings.Default.sync_resize_x, + this._manager.SyncPreviewSize(new Size((int)Properties.Settings.Default.sync_resize_x, (int)Properties.Settings.Default.sync_resize_y)); } private void option_sync_size_x_TextChanged(object sender, EventArgs e) { + if (!_isInitialized) + { + return; + } + parse_size_entry(); } private void option_sync_size_y_TextChanged(object sender, EventArgs e) { + if (!_isInitialized) + { + return; + } + parse_size_entry(); } private void option_always_on_top_CheckedChanged(object sender, EventArgs e) { + if (!_isInitialized) + { + return; + } + Properties.Settings.Default.always_on_top = option_always_on_top.Checked; Properties.Settings.Default.Save(); - refresh_thumbnails(); + this._manager.refresh_thumbnails(); } private void option_show_thumbnail_frames_CheckedChanged(object sender, EventArgs e) { + if (!_isInitialized) + { + return; + } + Properties.Settings.Default.show_thumb_frames = option_show_thumbnail_frames.Checked; Properties.Settings.Default.Save(); - if (Properties.Settings.Default.show_thumb_frames) - { - _ignoringSizeSync.Stop(); - _ignoringSizeSync.Reset(); - _ignoringSizeSync.Start(); - } - - foreach (var thumbnail in _previews) - { - thumbnail.Value.SetWindowFrames(Properties.Settings.Default.show_thumb_frames); - } - + this._manager.set_frames(); } - private void list_running_clients_SelectedIndexChanged(object sender, EventArgs e) { } @@ -685,24 +281,25 @@ namespace EveOPreview private void option_zoom_on_hover_CheckedChanged(object sender, EventArgs e) { + if (!_isInitialized) return; + Properties.Settings.Default.zoom_on_hover = option_zoom_on_hover.Checked; Properties.Settings.Default.Save(); - refresh_thumbnails(); + this._manager.refresh_thumbnails(); option_zoom_factor.Enabled = Properties.Settings.Default.zoom_on_hover; - if (_isInitialized) - { + foreach (var kv in _zoomAnchorButtonMap) { kv.Value.Enabled = Properties.Settings.Default.zoom_on_hover; } - } + } private void option_show_overlay_CheckedChanged(object sender, EventArgs e) { Properties.Settings.Default.show_overlay = option_show_overlay.Checked; Properties.Settings.Default.Save(); - refresh_thumbnails(); + this._manager.refresh_thumbnails(); } @@ -746,14 +343,14 @@ namespace EveOPreview private void checkedListBox1_SelectedIndexChanged(object sender, EventArgs e) { - refresh_thumbnails(); + this._manager.refresh_thumbnails(); } private void checkedListBox1_SelectedIndexChanged2(object sender, EventArgs e) { System.Windows.Forms.ItemCheckEventArgs arg = (System.Windows.Forms.ItemCheckEventArgs)e; ((ThumbnailWindow)this.previews_check_listbox.Items[arg.Index]).IsPreviewEnabled = (arg.NewValue != System.Windows.Forms.CheckState.Checked); - refresh_thumbnails(); + this._manager.refresh_thumbnails(); } private void flowLayoutPanel1_Paint(object sender, PaintEventArgs e) @@ -763,18 +360,26 @@ namespace EveOPreview private void checkBox1_CheckedChanged(object sender, EventArgs e) { + if (!_isInitialized) + { + return; + } Properties.Settings.Default.track_client_windows = option_track_client_windows.Checked; Properties.Settings.Default.Save(); - refresh_thumbnails(); + this._manager.refresh_thumbnails(); } private void opacity_bar_Scroll(object sender, ScrollEventArgs e) { + if (!_isInitialized) + { + return; + } // fire off opacity change Properties.Settings.Default.opacity = Math.Min((float)e.NewValue / 100.0f, 1.0f); Properties.Settings.Default.Save(); - refresh_thumbnails(); + this._manager.refresh_thumbnails(); } diff --git a/Eve-O-Preview/Thumbnail/ThumbnailFactory.cs b/Eve-O-Preview/Thumbnail/ThumbnailFactory.cs index a603043..f56fbf5 100644 --- a/Eve-O-Preview/Thumbnail/ThumbnailFactory.cs +++ b/Eve-O-Preview/Thumbnail/ThumbnailFactory.cs @@ -5,9 +5,9 @@ namespace EveOPreview { public class ThumbnailFactory { - public IThumbnail Create(MainForm parent, IntPtr sourceWindow, string title, Size size) + public IThumbnail Create(ThumbnailManager manager, IntPtr sourceWindow, string title, Size size) { - return new ThumbnailWindow(parent, sourceWindow, title, size); + return new ThumbnailWindow(manager, sourceWindow, title, size); } } } \ No newline at end of file diff --git a/Eve-O-Preview/Thumbnail/ThumbnailManager.cs b/Eve-O-Preview/Thumbnail/ThumbnailManager.cs new file mode 100644 index 0000000..3a52deb --- /dev/null +++ b/Eve-O-Preview/Thumbnail/ThumbnailManager.cs @@ -0,0 +1,507 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Windows.Threading; +using System.Xml.Linq; + +namespace EveOPreview +{ + public class ThumbnailManager + { + private readonly Stopwatch _ignoringSizeSync; + private DispatcherTimer _dispatcherTimer; + private readonly ThumbnailFactory _thumbnailFactory; + private readonly Dictionary _previews; + + private IntPtr _activeClientHandle; + private string _activeClientTitle; + + private readonly Dictionary> _uniqueLayouts; + private readonly Dictionary _flatLayout; + private readonly Dictionary _flatLayoutShortcuts; + private readonly Dictionary _clientLayout; + + private readonly Dictionary _xmlBadToOkChars; + + private readonly Action> _addThumbnail; + private readonly Action> _removeThumbnail; + private readonly Action _setAeroStatus; + private readonly Action _sizeChange; + + public ThumbnailManager(Action> addThumbnail, Action> removeThumbnail, Action setAeroStatus, Action sizeChange) + { + _addThumbnail = addThumbnail; + _removeThumbnail = removeThumbnail; + _setAeroStatus = setAeroStatus; + _sizeChange = sizeChange; + + _ignoringSizeSync = new Stopwatch(); + _ignoringSizeSync.Start(); + + this._activeClientHandle = (IntPtr)0; + this._activeClientTitle = ""; + + _xmlBadToOkChars = new Dictionary(); + _xmlBadToOkChars["<"] = "---lt---"; + _xmlBadToOkChars["&"] = "---amp---"; + _xmlBadToOkChars[">"] = "---gt---"; + _xmlBadToOkChars["\""] = "---quot---"; + _xmlBadToOkChars["\'"] = "---apos---"; + _xmlBadToOkChars[","] = "---comma---"; + _xmlBadToOkChars["."] = "---dot---"; + + _uniqueLayouts = new Dictionary>(); + _flatLayout = new Dictionary(); + _flatLayoutShortcuts = new Dictionary(); + _clientLayout = new Dictionary(); + + this._previews = new Dictionary(); + + // DispatcherTimer setup + _dispatcherTimer = new DispatcherTimer(); + _dispatcherTimer.Tick += dispatcherTimer_Tick; + _dispatcherTimer.Interval = new TimeSpan(0, 0, 1); + + this._thumbnailFactory = new ThumbnailFactory(); + } + + public void Activate() + { + this.load_layout(); + this._dispatcherTimer.Start(); + } + + public void Deactivate() + { + this._dispatcherTimer.Stop(); + } + + private void spawn_and_kill_previews() + { + // TODO Extract this! + Process[] processes = Process.GetProcessesByName("ExeFile"); + List processHandles = new List(); + List addedList=new List(); + List removedList = new List(); + // pop new previews + + foreach (Process process in processes) + { + processHandles.Add(process.MainWindowHandle); + + Size sync_size = new Size(); + sync_size.Width = (int)Properties.Settings.Default.sync_resize_x; + sync_size.Height = (int)Properties.Settings.Default.sync_resize_y; + + if (!_previews.ContainsKey(process.MainWindowHandle) && process.MainWindowTitle != "") + { + _previews[process.MainWindowHandle] = this._thumbnailFactory.Create(this, process.MainWindowHandle, "...", sync_size); + + // apply more thumbnail specific options + _previews[process.MainWindowHandle].SetTopMost(Properties.Settings.Default.always_on_top); + _previews[process.MainWindowHandle].SetWindowFrames(Properties.Settings.Default.show_thumb_frames); + + // add a preview also + addedList.Add(_previews[process.MainWindowHandle].GetLabel()); + + refresh_client_window_locations(process); + } + + else if (_previews.ContainsKey(process.MainWindowHandle) && process.MainWindowTitle != _previews[process.MainWindowHandle].GetLabel()) //or update the preview titles + { + _previews[process.MainWindowHandle].SetLabel(process.MainWindowTitle); + string key = _previews[process.MainWindowHandle].GetLabel(); + string value; + if (_flatLayoutShortcuts.TryGetValue(key, out value)) + { + _previews[process.MainWindowHandle].RegisterShortcut(value); + } + refresh_client_window_locations(process); + } + + if (process.MainWindowHandle == DwmApiNativeMethods.GetForegroundWindow()) + { + _activeClientHandle = process.MainWindowHandle; + _activeClientTitle = process.MainWindowTitle; + } + + } + + // TODO Check for empty list + _addThumbnail(addedList); + + // clean up old previews + List to_be_pruned = new List(); + foreach (IntPtr processHandle in _previews.Keys) + { + if (!(processHandles.Contains(processHandle))) + { + to_be_pruned.Add(processHandle); + } + } + + foreach (IntPtr processHandle in to_be_pruned) + { + removedList.Add(_previews[processHandle].GetLabel()); + + _previews[processHandle].CloseThumbnail(); + _previews.Remove(processHandle); + } + + _removeThumbnail(removedList); + } + + private void refresh_client_window_locations(Process process) + { + if (Properties.Settings.Default.track_client_windows && _clientLayout.ContainsKey(process.MainWindowTitle)) + { + DwmApiNativeMethods.MoveWindow(process.MainWindowHandle, _clientLayout[process.MainWindowTitle].X, + _clientLayout[process.MainWindowTitle].Y, _clientLayout[process.MainWindowTitle].Width, + _clientLayout[process.MainWindowTitle].Height, true); + } + } + + private void dispatcherTimer_Tick(object sender, EventArgs e) + { + spawn_and_kill_previews(); + refresh_thumbnails(); + if (_ignoringSizeSync.ElapsedMilliseconds > 500) { _ignoringSizeSync.Stop(); }; + + // TODO Do this once in 10 seconds + _setAeroStatus(DwmApiNativeMethods.DwmIsCompositionEnabled()); + } + + public void NotifyPreviewSwitch() + { + update_client_locations(); + store_layout(); //todo: check if it actually changed ... + foreach (KeyValuePair entry in _previews) + { + entry.Value.SetTopMost(Properties.Settings.Default.always_on_top); + } + } + + + public void SyncPreviewSize(Size sync_size) + { + if (Properties.Settings.Default.sync_resize && + Properties.Settings.Default.show_thumb_frames && + _ignoringSizeSync.ElapsedMilliseconds > 500) + { + _ignoringSizeSync.Stop(); + + _sizeChange(sync_size.Width, sync_size.Height); + + foreach (KeyValuePair entry in _previews) + { + if (entry.Value.IsPreviewHandle(DwmApiNativeMethods.GetForegroundWindow())) + { + entry.Value.SetSize(sync_size); + } + } + + } + + } + + + public void UpdatePreviewPosition(string preview_title, Point position) + { + + if (Properties.Settings.Default.unique_layout) + { + Dictionary layout; + if (_uniqueLayouts.TryGetValue(_activeClientTitle, out layout)) + { + layout[preview_title] = position; + } + else if (_activeClientTitle == "") + { + _uniqueLayouts[_activeClientTitle] = new Dictionary(); + _uniqueLayouts[_activeClientTitle][preview_title] = position; + } + } + else + { + _flatLayout[preview_title] = position; + } + + } + + private string remove_nonconform_xml_characters(string entry) + { + foreach (var kv in _xmlBadToOkChars) + { + entry = entry.Replace(kv.Key, kv.Value); + } + return entry; + } + + private string restore_nonconform_xml_characters(string entry) + { + foreach (var kv in _xmlBadToOkChars) + { + entry = entry.Replace(kv.Value, kv.Key); + } + return entry; + } + + private XElement MakeXElement(string input) + { + string clean = remove_nonconform_xml_characters(input).Replace(" ", "_"); + return new XElement(clean); + } + + private string ParseXElement(XElement input) + { + return restore_nonconform_xml_characters(input.Name.ToString()).Replace("_", " "); + } + + private void load_layout() + { + if (File.Exists("layout.xml")) + { + XElement rootElement = XElement.Load("layout.xml"); + foreach (var el in rootElement.Elements()) + { + Dictionary inner = new Dictionary(); + foreach (var inner_el in el.Elements()) + { + inner[ParseXElement(inner_el)] = new Point(Convert.ToInt32(inner_el.Element("x")?.Value), Convert.ToInt32(inner_el.Element("y")?.Value)); + } + _uniqueLayouts[ParseXElement(el)] = inner; + } + } + + if (File.Exists("flat_layout.xml")) + { + XElement rootElement = XElement.Load("flat_layout.xml"); + foreach (var el in rootElement.Elements()) + { + _flatLayout[ParseXElement(el)] = new Point(Convert.ToInt32(el.Element("x").Value), Convert.ToInt32(el.Element("y").Value)); + _flatLayoutShortcuts[ParseXElement(el)] = ""; + + if (el.Element("shortcut") != null) + { + _flatLayoutShortcuts[ParseXElement(el)] = el.Element("shortcut").Value; + } + } + } + + if (File.Exists("client_layout.xml")) + { + XElement rootElement = XElement.Load("client_layout.xml"); + foreach (var el in rootElement.Elements()) + { + ClientLocation clientLocation = new ClientLocation(); + clientLocation.X = Convert.ToInt32(el.Element("x").Value); + clientLocation.Y = Convert.ToInt32(el.Element("y").Value); + clientLocation.Width = Convert.ToInt32(el.Element("width").Value); + clientLocation.Height = Convert.ToInt32(el.Element("height").Value); + + _clientLayout[ParseXElement(el)] = clientLocation; + } + } + } + + private void store_layout() + { + XElement el = new XElement("layouts"); + foreach (var client in _uniqueLayouts.Keys) + { + if (client == "") + { + continue; + } + XElement layout = MakeXElement(client); + foreach (var thumbnail_ in _uniqueLayouts[client]) + { + string thumbnail = thumbnail_.Key; + if (thumbnail == "" || thumbnail == "...") + { + continue; + } + XElement position = MakeXElement(thumbnail); + position.Add(new XElement("x", thumbnail_.Value.X)); + position.Add(new XElement("y", thumbnail_.Value.Y)); + layout.Add(position); + } + el.Add(layout); + } + + el.Save("layout.xml"); + + XElement el2 = new XElement("flat_layout"); + foreach (var clientKV in _flatLayout) + { + if (clientKV.Key == "" || clientKV.Key == "...") + { + continue; + } + XElement layout = MakeXElement(clientKV.Key); + layout.Add(new XElement("x", clientKV.Value.X)); + layout.Add(new XElement("y", clientKV.Value.Y)); + + string shortcut; + if (_flatLayoutShortcuts.TryGetValue(clientKV.Key, out shortcut)) + { + layout.Add(new XElement("shortcut", shortcut)); + } + el2.Add(layout); + } + + el2.Save("flat_layout.xml"); + + XElement el3 = new XElement("client_layout"); + foreach (var clientKV in _clientLayout) + { + if (clientKV.Key == "" || clientKV.Key == "...") + { + continue; + } + XElement layout = MakeXElement(clientKV.Key); + layout.Add(new XElement("x", clientKV.Value.X)); + layout.Add(new XElement("y", clientKV.Value.Y)); + layout.Add(new XElement("width", clientKV.Value.Width)); + layout.Add(new XElement("height", clientKV.Value.Height)); + el3.Add(layout); + } + + el3.Save("client_layout.xml"); + } + + private void handle_unique_layout(IThumbnail thumbnailWindow, string last_known_active_window) + { + Dictionary layout; + if (_uniqueLayouts.TryGetValue(last_known_active_window, out layout)) + { + Point new_loc; + if (Properties.Settings.Default.unique_layout && layout.TryGetValue(thumbnailWindow.GetLabel(), out new_loc)) + { + thumbnailWindow.SetLocation(new_loc); + } + else + { + // create inner dict + layout[thumbnailWindow.GetLabel()] = thumbnailWindow.GetLocation(); + } + } + else if (last_known_active_window != "") + { + // create outer dict + _uniqueLayouts[last_known_active_window] = new Dictionary(); + _uniqueLayouts[last_known_active_window][thumbnailWindow.GetLabel()] = thumbnailWindow.GetLocation(); + } + } + + private void update_client_locations() + { + Process[] processes = Process.GetProcessesByName("ExeFile"); + List processHandles = new List(); + + foreach (Process process in processes) + { + RECT rect = new RECT(); + DwmApiNativeMethods.GetWindowRect(process.MainWindowHandle, out rect); + + int left = Math.Abs(rect.Left); + int right = Math.Abs(rect.Right); + int client_width = Math.Abs(left - right); + + int top = Math.Abs(rect.Top); + int bottom = Math.Abs(rect.Bottom); + int client_height = Math.Abs(top - bottom); + + ClientLocation clientLocation = new ClientLocation(); + clientLocation.X = rect.Left; + clientLocation.Y = rect.Top; + clientLocation.Width = client_width; + clientLocation.Height = client_height; + + + _clientLayout[process.MainWindowTitle] = clientLocation; + } + } + + private void handle_flat_layout(IThumbnail thumbnailWindow) + { + Point layout; + if (_flatLayout.TryGetValue(thumbnailWindow.GetLabel(), out layout)) + { + thumbnailWindow.SetLocation(layout); + } + else if (thumbnailWindow.GetLabel() != "") + { + _flatLayout[thumbnailWindow.GetLabel()] = thumbnailWindow.GetLocation(); + } + } + + private bool window_is_preview_or_client(IntPtr window) + { + bool active_window_is_right_type = false; + foreach (KeyValuePair entry in _previews) + { + if (entry.Key == window || entry.Value.IsPreviewHandle(window)) + { + active_window_is_right_type = true; + } + } + return active_window_is_right_type; + } + + public void refresh_thumbnails() + { + + IntPtr active_window = DwmApiNativeMethods.GetForegroundWindow(); + + // hide, show, resize and move + foreach (KeyValuePair entry in _previews) + { + if (!window_is_preview_or_client(active_window) && Properties.Settings.Default.hide_all) + { + entry.Value.HideThumbnail(); + } + else if (entry.Key == _activeClientHandle && Properties.Settings.Default.hide_active) + { + entry.Value.HideThumbnail(); + } + else + { + entry.Value.ShowThumbnail(); + if (Properties.Settings.Default.unique_layout) + { + handle_unique_layout(entry.Value, _activeClientTitle); + } + else + { + handle_flat_layout(entry.Value); + } + } + entry.Value.IsZoomEnabled = Properties.Settings.Default.zoom_on_hover; + entry.Value.IsOverlayEnabled = Properties.Settings.Default.show_overlay; + entry.Value.SetOpacity(Properties.Settings.Default.opacity); + } + + DwmApiNativeMethods.DwmIsCompositionEnabled(); + } + + public void set_frames() + { + if (Properties.Settings.Default.show_thumb_frames) + { + _ignoringSizeSync.Stop(); + _ignoringSizeSync.Reset(); + _ignoringSizeSync.Start(); + } + + foreach (var thumbnail in _previews) + { + thumbnail.Value.SetWindowFrames(Properties.Settings.Default.show_thumb_frames); + } + + } + + } +} \ No newline at end of file diff --git a/Eve-O-Preview/Thumbnail/ThumbnailWindow.cs b/Eve-O-Preview/Thumbnail/ThumbnailWindow.cs index 71c05c9..1f24b27 100644 --- a/Eve-O-Preview/Thumbnail/ThumbnailWindow.cs +++ b/Eve-O-Preview/Thumbnail/ThumbnailWindow.cs @@ -9,7 +9,7 @@ namespace EveOPreview #region Private fields private readonly bool _isInitializing; private readonly IntPtr _sourceWindow; - private readonly MainForm _parentForm; + private readonly ThumbnailManager _manager; private readonly ThumbnailOverlay _overlay; private Hotkey _hotkey; // This field stores the hotkey reference @@ -26,7 +26,7 @@ namespace EveOPreview #endregion // This constructor should never be used directly - public ThumbnailWindow(MainForm parent, IntPtr sourceWindow, string title, Size size) + public ThumbnailWindow(ThumbnailManager manager, IntPtr sourceWindow, string title, Size size) { this._isInitializing = true; @@ -34,7 +34,7 @@ namespace EveOPreview this.IsOverlayEnabled = true; this._sourceWindow = sourceWindow; - this._parentForm = parent; + this._manager = manager; this._isThumbnailSetUp = false; this._ignoreMouseOverEvent = false; @@ -248,7 +248,7 @@ namespace EveOPreview if (e.Button == MouseButtons.Left) { this.ActivateClient(); - this._parentForm.NotifyPreviewSwitch(); + this._manager.NotifyPreviewSwitch(); } if (e.Button == MouseButtons.Right) @@ -265,7 +265,7 @@ namespace EveOPreview private void Hotkey_Pressed(Object sender, EventArgs e) { this.ActivateClient(); - this._parentForm.NotifyPreviewSwitch(); + this._manager.NotifyPreviewSwitch(); } protected override void OnResize(EventArgs e) @@ -276,7 +276,7 @@ namespace EveOPreview if (!(this._isInitializing || this._ignoreMouseOverEvent)) { - this._parentForm.SyncPreviewSize(this.Size); + this._manager.SyncPreviewSize(this.Size); } } @@ -286,7 +286,7 @@ namespace EveOPreview if (!(this._isInitializing || this._ignoreMouseOverEvent)) { - this._parentForm.UpdatePreviewPosition(this.Text, this.Location); + this._manager.UpdatePreviewPosition(this.Text, this.Location); } this.RefreshPreview();