Extreact Thumbnail and Settings management code from main form

This commit is contained in:
Anton Kasyanov
2016-05-20 21:41:58 +03:00
parent a6f5e2edec
commit a8a93b11ba
7 changed files with 644 additions and 515 deletions

View File

@@ -0,0 +1,7 @@
namespace EveOPreview
{
public class Configuration
{
}
}

View File

@@ -0,0 +1,7 @@
namespace EveOPreview.Managers
{
public class ConfigurationStorage
{
}
}

View File

@@ -110,6 +110,7 @@
<Compile Include="DwmAPI\RECT.cs" /> <Compile Include="DwmAPI\RECT.cs" />
<Compile Include="GUI\ClientLocation.cs" /> <Compile Include="GUI\ClientLocation.cs" />
<Compile Include="GUI\ZoomAnchor.cs" /> <Compile Include="GUI\ZoomAnchor.cs" />
<Compile Include="Configuration\Configuration.cs" />
<Compile Include="Hotkeys\Hotkey.cs" /> <Compile Include="Hotkeys\Hotkey.cs" />
<Compile Include="Hotkeys\HotkeyNativeMethods.cs" /> <Compile Include="Hotkeys\HotkeyNativeMethods.cs" />
<Compile Include="GUI\MainForm.cs"> <Compile Include="GUI\MainForm.cs">
@@ -118,8 +119,10 @@
<Compile Include="GUI\MainForm.Designer.cs"> <Compile Include="GUI\MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon> <DependentUpon>MainForm.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Configuration\ConfigurationStorage.cs" />
<Compile Include="Thumbnail\IThumbnail.cs" /> <Compile Include="Thumbnail\IThumbnail.cs" />
<Compile Include="Thumbnail\ThumbnailFactory.cs" /> <Compile Include="Thumbnail\ThumbnailFactory.cs" />
<Compile Include="Thumbnail\ThumbnailManager.cs" />
<Compile Include="Thumbnail\ThumbnailOverlay.cs"> <Compile Include="Thumbnail\ThumbnailOverlay.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>

View File

@@ -12,29 +12,13 @@ namespace EveOPreview
{ {
public partial class MainForm : Form public partial class MainForm : Form
{ {
private readonly ThumbnailFactory _thumbnailFactory;
public event EventHandler Minimized; public event EventHandler Minimized;
public event EventHandler Maximized; public event EventHandler Maximized;
public event EventHandler Restored; public event EventHandler Restored;
private readonly Dictionary<IntPtr, IThumbnail> _previews;
private DispatcherTimer _dispatcherTimer;
private IntPtr _activeClientHandle;
private string _activeClientTitle;
private readonly Dictionary<string, Dictionary<string, Point>> _uniqueLayouts;
private readonly Dictionary<string, Point> _flatLayout;
private readonly Dictionary<string, string> _flatLayoutShortcuts;
private readonly Dictionary<string, ClientLocation> _clientLayout;
private readonly bool _isInitialized; private readonly bool _isInitialized;
private readonly ThumbnailManager _manager;
private readonly Stopwatch _ignoringSizeSync;
private readonly Dictionary<string, string> _xmlBadToOkChars;
private Dictionary<ZoomAnchor, RadioButton> _zoomAnchorButtonMap; private Dictionary<ZoomAnchor, RadioButton> _zoomAnchorButtonMap;
@@ -42,49 +26,63 @@ namespace EveOPreview
{ {
_isInitialized = false; _isInitialized = false;
this._activeClientHandle = (IntPtr)0;
this._activeClientTitle = "";
this._previews = new Dictionary<IntPtr, IThumbnail>();
_xmlBadToOkChars = new Dictionary<string, string>();
_xmlBadToOkChars["<"] = "---lt---";
_xmlBadToOkChars["&"] = "---amp---";
_xmlBadToOkChars[">"] = "---gt---";
_xmlBadToOkChars["\""] = "---quot---";
_xmlBadToOkChars["\'"] = "---apos---";
_xmlBadToOkChars[","] = "---comma---";
_xmlBadToOkChars["."] = "---dot---";
_uniqueLayouts = new Dictionary<string, Dictionary<string, Point>>();
_flatLayout = new Dictionary<string, Point>();
_flatLayoutShortcuts = new Dictionary<string, string>();
_clientLayout = new Dictionary<string, ClientLocation>();
_ignoringSizeSync = new Stopwatch();
_ignoringSizeSync.Start();
InitializeComponent(); InitializeComponent();
init_options(); init_options();
// DispatcherTimer setup // TODO Fix this
_dispatcherTimer = new DispatcherTimer(); previews_check_listbox.DisplayMember = "Text";
_dispatcherTimer.Tick += dispatcherTimer_Tick;
_dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
_dispatcherTimer.Start();
this._thumbnailFactory = new ThumbnailFactory(); this._manager = new ThumbnailManager(add_thumbnail,remove_thumbnail, set_aero_status, set_size);
_isInitialized = true; _isInitialized = true;
previews_check_listbox.DisplayMember = "Text"; this._manager.Activate();
} }
private void add_thumbnail(IList<string> 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<string> 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) private void GlassForm_Load(object sender, EventArgs e)
{ {
refresh_thumbnails(); this._manager.refresh_thumbnails();
} }
private void init_options() private void init_options()
@@ -131,470 +129,60 @@ namespace EveOPreview
} }
opacity_bar.Value = Math.Min(100, (int)(100.0 * Properties.Settings.Default.opacity)); 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<IntPtr> processHandles = new List<IntPtr>();
// 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<IntPtr> to_be_pruned = new List<IntPtr>();
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<string, Point> inner = new Dictionary<string, Point>();
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<string, Point> 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<string, Point>();
_uniqueLayouts[last_known_active_window][thumbnailWindow.GetLabel()] = thumbnailWindow.GetLocation();
}
}
private void update_client_locations()
{
Process[] processes = Process.GetProcessesByName("ExeFile");
List<IntPtr> processHandles = new List<IntPtr>();
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<IntPtr, IThumbnail> 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<IntPtr, IThumbnail> 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<IntPtr, IThumbnail> 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<IntPtr, IThumbnail> 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<string, Point> layout;
if (_uniqueLayouts.TryGetValue(_activeClientTitle, out layout))
{
layout[preview_title] = position;
}
else if (_activeClientTitle == "")
{
_uniqueLayouts[_activeClientTitle] = new Dictionary<string, Point>();
_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) 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.hide_all = option_hide_all_if_not_right_type.Checked;
Properties.Settings.Default.Save(); Properties.Settings.Default.Save();
refresh_thumbnails(); this._manager.refresh_thumbnails();
} }
private void option_unique_layout_CheckedChanged(object sender, EventArgs e) 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.unique_layout = option_unique_layout.Checked;
Properties.Settings.Default.Save(); Properties.Settings.Default.Save();
refresh_thumbnails(); this._manager.refresh_thumbnails();
} }
private void option_hide_active_CheckedChanged(object sender, EventArgs e) 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.hide_active = option_hide_active.Checked;
Properties.Settings.Default.Save(); Properties.Settings.Default.Save();
refresh_thumbnails(); this._manager.refresh_thumbnails();
} }
private void option_sync_size_CheckedChanged(object sender, EventArgs e) 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.sync_resize = option_sync_size.Checked;
Properties.Settings.Default.Save(); Properties.Settings.Default.Save();
refresh_thumbnails(); this._manager.refresh_thumbnails();
} }
@@ -622,51 +210,59 @@ namespace EveOPreview
Properties.Settings.Default.Save(); Properties.Settings.Default.Save();
// resize // 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)); (int)Properties.Settings.Default.sync_resize_y));
} }
private void option_sync_size_x_TextChanged(object sender, EventArgs e) private void option_sync_size_x_TextChanged(object sender, EventArgs e)
{ {
if (!_isInitialized)
{
return;
}
parse_size_entry(); parse_size_entry();
} }
private void option_sync_size_y_TextChanged(object sender, EventArgs e) private void option_sync_size_y_TextChanged(object sender, EventArgs e)
{ {
if (!_isInitialized)
{
return;
}
parse_size_entry(); parse_size_entry();
} }
private void option_always_on_top_CheckedChanged(object sender, EventArgs e) 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.always_on_top = option_always_on_top.Checked;
Properties.Settings.Default.Save(); Properties.Settings.Default.Save();
refresh_thumbnails(); this._manager.refresh_thumbnails();
} }
private void option_show_thumbnail_frames_CheckedChanged(object sender, EventArgs e) 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.show_thumb_frames = option_show_thumbnail_frames.Checked;
Properties.Settings.Default.Save(); Properties.Settings.Default.Save();
if (Properties.Settings.Default.show_thumb_frames) this._manager.set_frames();
{
_ignoringSizeSync.Stop();
_ignoringSizeSync.Reset();
_ignoringSizeSync.Start();
} }
foreach (var thumbnail in _previews)
{
thumbnail.Value.SetWindowFrames(Properties.Settings.Default.show_thumb_frames);
}
}
private void list_running_clients_SelectedIndexChanged(object sender, EventArgs e) { } 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) 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.zoom_on_hover = option_zoom_on_hover.Checked;
Properties.Settings.Default.Save(); Properties.Settings.Default.Save();
refresh_thumbnails(); this._manager.refresh_thumbnails();
option_zoom_factor.Enabled = Properties.Settings.Default.zoom_on_hover; option_zoom_factor.Enabled = Properties.Settings.Default.zoom_on_hover;
if (_isInitialized)
{
foreach (var kv in _zoomAnchorButtonMap) foreach (var kv in _zoomAnchorButtonMap)
{ {
kv.Value.Enabled = Properties.Settings.Default.zoom_on_hover; kv.Value.Enabled = Properties.Settings.Default.zoom_on_hover;
} }
}
} }
private void option_show_overlay_CheckedChanged(object sender, EventArgs e) private void option_show_overlay_CheckedChanged(object sender, EventArgs e)
{ {
Properties.Settings.Default.show_overlay = option_show_overlay.Checked; Properties.Settings.Default.show_overlay = option_show_overlay.Checked;
Properties.Settings.Default.Save(); Properties.Settings.Default.Save();
refresh_thumbnails(); this._manager.refresh_thumbnails();
} }
@@ -746,14 +343,14 @@ namespace EveOPreview
private void checkedListBox1_SelectedIndexChanged(object sender, EventArgs e) private void checkedListBox1_SelectedIndexChanged(object sender, EventArgs e)
{ {
refresh_thumbnails(); this._manager.refresh_thumbnails();
} }
private void checkedListBox1_SelectedIndexChanged2(object sender, EventArgs e) private void checkedListBox1_SelectedIndexChanged2(object sender, EventArgs e)
{ {
System.Windows.Forms.ItemCheckEventArgs arg = (System.Windows.Forms.ItemCheckEventArgs)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); ((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) private void flowLayoutPanel1_Paint(object sender, PaintEventArgs e)
@@ -763,18 +360,26 @@ namespace EveOPreview
private void checkBox1_CheckedChanged(object sender, EventArgs e) 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.track_client_windows = option_track_client_windows.Checked;
Properties.Settings.Default.Save(); Properties.Settings.Default.Save();
refresh_thumbnails(); this._manager.refresh_thumbnails();
} }
private void opacity_bar_Scroll(object sender, ScrollEventArgs e) private void opacity_bar_Scroll(object sender, ScrollEventArgs e)
{ {
if (!_isInitialized)
{
return;
}
// fire off opacity change // fire off opacity change
Properties.Settings.Default.opacity = Math.Min((float)e.NewValue / 100.0f, 1.0f); Properties.Settings.Default.opacity = Math.Min((float)e.NewValue / 100.0f, 1.0f);
Properties.Settings.Default.Save(); Properties.Settings.Default.Save();
refresh_thumbnails(); this._manager.refresh_thumbnails();
} }

View File

@@ -5,9 +5,9 @@ namespace EveOPreview
{ {
public class ThumbnailFactory 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);
} }
} }
} }

View File

@@ -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<IntPtr, IThumbnail> _previews;
private IntPtr _activeClientHandle;
private string _activeClientTitle;
private readonly Dictionary<string, Dictionary<string, Point>> _uniqueLayouts;
private readonly Dictionary<string, Point> _flatLayout;
private readonly Dictionary<string, string> _flatLayoutShortcuts;
private readonly Dictionary<string, ClientLocation> _clientLayout;
private readonly Dictionary<string, string> _xmlBadToOkChars;
private readonly Action<IList<string>> _addThumbnail;
private readonly Action<IList<string>> _removeThumbnail;
private readonly Action<bool> _setAeroStatus;
private readonly Action<int,int> _sizeChange;
public ThumbnailManager(Action<IList<string>> addThumbnail, Action<IList<string>> removeThumbnail, Action<bool> setAeroStatus, Action<int,int> sizeChange)
{
_addThumbnail = addThumbnail;
_removeThumbnail = removeThumbnail;
_setAeroStatus = setAeroStatus;
_sizeChange = sizeChange;
_ignoringSizeSync = new Stopwatch();
_ignoringSizeSync.Start();
this._activeClientHandle = (IntPtr)0;
this._activeClientTitle = "";
_xmlBadToOkChars = new Dictionary<string, string>();
_xmlBadToOkChars["<"] = "---lt---";
_xmlBadToOkChars["&"] = "---amp---";
_xmlBadToOkChars[">"] = "---gt---";
_xmlBadToOkChars["\""] = "---quot---";
_xmlBadToOkChars["\'"] = "---apos---";
_xmlBadToOkChars[","] = "---comma---";
_xmlBadToOkChars["."] = "---dot---";
_uniqueLayouts = new Dictionary<string, Dictionary<string, Point>>();
_flatLayout = new Dictionary<string, Point>();
_flatLayoutShortcuts = new Dictionary<string, string>();
_clientLayout = new Dictionary<string, ClientLocation>();
this._previews = new Dictionary<IntPtr, IThumbnail>();
// 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<IntPtr> processHandles = new List<IntPtr>();
List<string> addedList=new List<string>();
List<string> removedList = new List<string>();
// 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<IntPtr> to_be_pruned = new List<IntPtr>();
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<IntPtr, IThumbnail> 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<IntPtr, IThumbnail> 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<string, Point> layout;
if (_uniqueLayouts.TryGetValue(_activeClientTitle, out layout))
{
layout[preview_title] = position;
}
else if (_activeClientTitle == "")
{
_uniqueLayouts[_activeClientTitle] = new Dictionary<string, Point>();
_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<string, Point> inner = new Dictionary<string, Point>();
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<string, Point> 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<string, Point>();
_uniqueLayouts[last_known_active_window][thumbnailWindow.GetLabel()] = thumbnailWindow.GetLocation();
}
}
private void update_client_locations()
{
Process[] processes = Process.GetProcessesByName("ExeFile");
List<IntPtr> processHandles = new List<IntPtr>();
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<IntPtr, IThumbnail> 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<IntPtr, IThumbnail> 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);
}
}
}
}

View File

@@ -9,7 +9,7 @@ namespace EveOPreview
#region Private fields #region Private fields
private readonly bool _isInitializing; private readonly bool _isInitializing;
private readonly IntPtr _sourceWindow; private readonly IntPtr _sourceWindow;
private readonly MainForm _parentForm; private readonly ThumbnailManager _manager;
private readonly ThumbnailOverlay _overlay; private readonly ThumbnailOverlay _overlay;
private Hotkey _hotkey; // This field stores the hotkey reference private Hotkey _hotkey; // This field stores the hotkey reference
@@ -26,7 +26,7 @@ namespace EveOPreview
#endregion #endregion
// This constructor should never be used directly // 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; this._isInitializing = true;
@@ -34,7 +34,7 @@ namespace EveOPreview
this.IsOverlayEnabled = true; this.IsOverlayEnabled = true;
this._sourceWindow = sourceWindow; this._sourceWindow = sourceWindow;
this._parentForm = parent; this._manager = manager;
this._isThumbnailSetUp = false; this._isThumbnailSetUp = false;
this._ignoreMouseOverEvent = false; this._ignoreMouseOverEvent = false;
@@ -248,7 +248,7 @@ namespace EveOPreview
if (e.Button == MouseButtons.Left) if (e.Button == MouseButtons.Left)
{ {
this.ActivateClient(); this.ActivateClient();
this._parentForm.NotifyPreviewSwitch(); this._manager.NotifyPreviewSwitch();
} }
if (e.Button == MouseButtons.Right) if (e.Button == MouseButtons.Right)
@@ -265,7 +265,7 @@ namespace EveOPreview
private void Hotkey_Pressed(Object sender, EventArgs e) private void Hotkey_Pressed(Object sender, EventArgs e)
{ {
this.ActivateClient(); this.ActivateClient();
this._parentForm.NotifyPreviewSwitch(); this._manager.NotifyPreviewSwitch();
} }
protected override void OnResize(EventArgs e) protected override void OnResize(EventArgs e)
@@ -276,7 +276,7 @@ namespace EveOPreview
if (!(this._isInitializing || this._ignoreMouseOverEvent)) 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)) if (!(this._isInitializing || this._ignoreMouseOverEvent))
{ {
this._parentForm.UpdatePreviewPosition(this.Text, this.Location); this._manager.UpdatePreviewPosition(this.Text, this.Location);
} }
this.RefreshPreview(); this.RefreshPreview();