Thumbnail management code cleanup

This commit is contained in:
Anton Kasyanov
2016-05-30 23:13:39 +03:00
parent 362fd0b8d4
commit 244a193e99
28 changed files with 1207 additions and 1115 deletions

View File

@@ -0,0 +1,11 @@
namespace EveOPreview
{
public class WindowProperties
{
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
}
}

View File

@@ -116,22 +116,22 @@
<Compile Include="DwmAPI\DWM_TNP_CONSTANTS.cs" /> <Compile Include="DwmAPI\DWM_TNP_CONSTANTS.cs" />
<Compile Include="DwmAPI\MARGINS.cs" /> <Compile Include="DwmAPI\MARGINS.cs" />
<Compile Include="DwmAPI\RECT.cs" /> <Compile Include="DwmAPI\RECT.cs" />
<Compile Include="GUI\ClientLocation.cs" /> <Compile Include="Configuration\WindowProperties.cs" />
<Compile Include="ApplicationBase\IPresenter.cs" /> <Compile Include="ApplicationBase\IPresenter.cs" />
<Compile Include="Presentation\MainPresenter.cs" /> <Compile Include="Presentation\MainPresenter.cs" />
<Compile Include="Presentation\ViewCloseRequest.cs" /> <Compile Include="Presentation\ViewCloseRequest.cs" />
<Compile Include="Thumbnail\Interface\IThumbnailFactory.cs" /> <Compile Include="UI\Interface\IThumbnailViewFactory.cs" />
<Compile Include="Thumbnail\Interface\IThumbnailManager.cs" /> <Compile Include="Presentation\IThumbnailManager.cs" />
<Compile Include="UI\Implementation\ThumbnailDescriptionView.cs" /> <Compile Include="UI\Implementation\ThumbnailDescriptionView.cs" />
<Compile Include="UI\Implementation\ThumbnailDescriptionViewFactory.cs" /> <Compile Include="UI\Factory\ThumbnailDescriptionViewFactory.cs" />
<Compile Include="UI\Interface\IMainView.cs" /> <Compile Include="UI\Interface\IMainView.cs" />
<Compile Include="ApplicationBase\IView.cs" /> <Compile Include="ApplicationBase\IView.cs" />
<Compile Include="UI\Interface\IThumbnailDescriptionView.cs" /> <Compile Include="UI\Interface\IThumbnailDescriptionView.cs" />
<Compile Include="UI\Interface\IThumbnailDescriptionViewFactory.cs" /> <Compile Include="UI\Interface\IThumbnailDescriptionViewFactory.cs" />
<Compile Include="UI\Interface\ZoomAnchor.cs" /> <Compile Include="UI\Interface\ZoomAnchor.cs" />
<Compile Include="Configuration\Configuration.cs" /> <Compile Include="Configuration\Configuration.cs" />
<Compile Include="Hotkeys\Hotkey.cs" /> <None Include="Hotkeys\Hotkey.cs" />
<Compile Include="Hotkeys\HotkeyNativeMethods.cs" /> <None Include="Hotkeys\HotkeyNativeMethods.cs" />
<Compile Include="UI\Implementation\MainForm.cs"> <Compile Include="UI\Implementation\MainForm.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>
@@ -139,13 +139,13 @@
<DependentUpon>MainForm.cs</DependentUpon> <DependentUpon>MainForm.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Configuration\ConfigurationStorage.cs" /> <Compile Include="Configuration\ConfigurationStorage.cs" />
<Compile Include="Thumbnail\Interface\IThumbnail.cs" /> <Compile Include="UI\Interface\IThumbnailView.cs" />
<Compile Include="Thumbnail\Implementation\ThumbnailFactory.cs" /> <Compile Include="UI\Factory\ThumbnailViewFactory.cs" />
<Compile Include="Thumbnail\Implementation\ThumbnailManager.cs" /> <Compile Include="Presentation\ThumbnailManager.cs" />
<Compile Include="Thumbnail\Implementation\ThumbnailOverlay.cs"> <Compile Include="UI\Implementation\ThumbnailOverlay.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>
<Compile Include="Thumbnail\Implementation\ThumbnailOverlay.Designer.cs"> <Compile Include="UI\Implementation\ThumbnailOverlay.Designer.cs">
<DependentUpon>ThumbnailOverlay.cs</DependentUpon> <DependentUpon>ThumbnailOverlay.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
@@ -154,7 +154,7 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<DependentUpon>MainForm.cs</DependentUpon> <DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Thumbnail\Implementation\ThumbnailOverlay.resx"> <EmbeddedResource Include="UI\Implementation\ThumbnailOverlay.resx">
<DependentUpon>ThumbnailOverlay.cs</DependentUpon> <DependentUpon>ThumbnailOverlay.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx"> <EmbeddedResource Include="Properties\Resources.resx">
@@ -162,9 +162,9 @@
<LastGenOutput>Resources.Designer.cs</LastGenOutput> <LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Thumbnail\Implementation\ThumbnailWindow.resx"> <EmbeddedResource Include="UI\Implementation\ThumbnailView.resx">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<DependentUpon>ThumbnailWindow.cs</DependentUpon> <DependentUpon>ThumbnailView.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs"> <Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
@@ -184,11 +184,11 @@
<DependentUpon>Settings.settings</DependentUpon> <DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput> <DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile> </Compile>
<Compile Include="Thumbnail\Implementation\ThumbnailWindow.cs"> <Compile Include="UI\Implementation\ThumbnailView.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>
<Compile Include="Thumbnail\Implementation\ThumbnailWindow.Designer.cs"> <Compile Include="UI\Implementation\ThumbnailView.Designer.cs">
<DependentUpon>ThumbnailWindow.cs</DependentUpon> <DependentUpon>ThumbnailView.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="DwmAPI\DwmApiNativeMethods.cs" /> <Compile Include="DwmAPI\DwmApiNativeMethods.cs" />
</ItemGroup> </ItemGroup>
@@ -220,7 +220,9 @@
<ItemGroup> <ItemGroup>
<Content Include="icon.ico" /> <Content Include="icon.ico" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup>
<Folder Include="GUI\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -1,10 +0,0 @@
namespace EveOPreview
{
public struct ClientLocation
{
public int X;
public int Y;
public int Width;
public int Height;
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Drawing;
namespace EveOPreview.UI
{
public interface IThumbnailManager
{
void Activate();
void SetThumbnailState(IntPtr thumbnailId, bool hideAlways);
void SetThumbnailsSize(Size size);
void RefreshThumbnails();
void SetupThumbnailFrames();
event Action<IList<IThumbnailView>> ThumbnailsAdded;
event Action<IList<IThumbnailView>> ThumbnailsUpdated;
event Action<IList<IThumbnailView>> ThumbnailsRemoved;
event Action<Size> ThumbnailSizeChanged;
}
}

View File

@@ -2,7 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing; using System.Drawing;
using EveOPreview.Thumbnails;
namespace EveOPreview.UI namespace EveOPreview.UI
{ {
@@ -78,7 +77,7 @@ namespace EveOPreview.UI
private void UpdateThumbnailsSize() private void UpdateThumbnailsSize()
{ {
this._manager.SyncPreviewSize(new Size(this.View.ThumbnailsWidth, this.View.ThumbnailsHeight)); this._manager.SetThumbnailsSize(new Size(this.View.ThumbnailsWidth, this.View.ThumbnailsHeight));
this.SaveApplicationSettings(); this.SaveApplicationSettings();
} }
@@ -134,29 +133,29 @@ namespace EveOPreview.UI
this._manager.RefreshThumbnails(); this._manager.RefreshThumbnails();
} }
private void ThumbnailsAdded(IList<IThumbnail> thumbnails) private void ThumbnailsAdded(IList<IThumbnailView> thumbnails)
{ {
this.View.AddThumbnails(this.GetThumbnailViews(thumbnails, false)); this.View.AddThumbnails(this.GetThumbnailViews(thumbnails, false));
} }
private void ThumbnailsUpdated(IList<IThumbnail> thumbnails) private void ThumbnailsUpdated(IList<IThumbnailView> thumbnails)
{ {
this.View.UpdateThumbnails(this.GetThumbnailViews(thumbnails, false)); this.View.UpdateThumbnails(this.GetThumbnailViews(thumbnails, false));
} }
private void ThumbnailsRemoved(IList<IThumbnail> thumbnails) private void ThumbnailsRemoved(IList<IThumbnailView> thumbnails)
{ {
this.View.RemoveThumbnails(this.GetThumbnailViews(thumbnails, true)); this.View.RemoveThumbnails(this.GetThumbnailViews(thumbnails, true));
} }
private IList<IThumbnailDescriptionView> GetThumbnailViews(IList<IThumbnail> thumbnails, bool removeFromCache) private IList<IThumbnailDescriptionView> GetThumbnailViews(IList<IThumbnailView> thumbnails, bool removeFromCache)
{ {
IList<IThumbnailDescriptionView> thumbnailViews = new List<IThumbnailDescriptionView>(thumbnails.Count); IList<IThumbnailDescriptionView> thumbnailViews = new List<IThumbnailDescriptionView>(thumbnails.Count);
// Time for some thread safety // Time for some thread safety
lock (this._thumbnailViews) lock (this._thumbnailViews)
{ {
foreach (IThumbnail thumbnail in thumbnails) foreach (IThumbnailView thumbnail in thumbnails)
{ {
IThumbnailDescriptionView thumbnailView; IThumbnailDescriptionView thumbnailView;
bool foundInCache = this._thumbnailViews.TryGetValue(thumbnail.Id, out thumbnailView); bool foundInCache = this._thumbnailViews.TryGetValue(thumbnail.Id, out thumbnailView);
@@ -169,7 +168,7 @@ namespace EveOPreview.UI
continue; continue;
} }
thumbnailView = this._thumbnailDescriptionViewFactory.Create(thumbnail.Id, thumbnail.GetLabel()); thumbnailView = this._thumbnailDescriptionViewFactory.Create(thumbnail.Id, thumbnail.Title, !thumbnail.IsEnabled);
this._thumbnailViews.Add(thumbnail.Id, thumbnailView); this._thumbnailViews.Add(thumbnail.Id, thumbnailView);
} }
else else
@@ -180,7 +179,7 @@ namespace EveOPreview.UI
} }
else else
{ {
thumbnailView.Title = thumbnail.GetLabel(); thumbnailView.Title = thumbnail.Title;
} }
} }
@@ -196,9 +195,9 @@ namespace EveOPreview.UI
this.View.UpdateThumbnailsSizeView(size); this.View.UpdateThumbnailsSizeView(size);
} }
private void UpdateThumbnailState(IntPtr thumbnailId, bool hideAlways) private void UpdateThumbnailState(IntPtr thumbnailId)
{ {
this._manager.SetThumbnailState(thumbnailId, hideAlways); this._manager.SetThumbnailState(thumbnailId, this._thumbnailViews[thumbnailId].IsDisabled);
} }
private void OpenForumUrlLink() private void OpenForumUrlLink()

View File

@@ -0,0 +1,746 @@
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.UI
{
public class ThumbnailManager : IThumbnailManager
{
private const string ClientProcessName = "ExeFile";
private const string DefaultThumbnailTitle = "...";
private readonly DispatcherTimer _thumbnailUpdateTimer;
private readonly IThumbnailViewFactory _thumbnailViewFactory;
private readonly Dictionary<IntPtr, IThumbnailView> _thumbnailViews;
private IntPtr _activeClientHandle;
private string _activeClientTitle;
private bool _ignoreViewEvents;
private bool _isHoverEffectActive;
private Size _thumbnailBaseSize;
private Point _thumbnailBaseLocation;
// TODO To be moved into a separate class
private readonly Dictionary<string, Dictionary<string, Point>> _uniqueLayouts;
private readonly Dictionary<string, Point> _flatLayout;
private readonly Dictionary<string, string> _flatLayoutShortcuts;
private readonly Dictionary<string, WindowProperties> _clientLayout;
// TODO To be removed
private readonly Dictionary<string, string> _xmlBadToOkChars;
// TODO Drop dependency on the configuration object
public ThumbnailManager(IThumbnailViewFactory factory)
{
this._thumbnailViewFactory = factory;
this._activeClientHandle = (IntPtr)0;
this._activeClientTitle = "";
this._ignoreViewEvents = false;
this._isHoverEffectActive = false;
this._thumbnailViews = new Dictionary<IntPtr, IThumbnailView>();
// DispatcherTimer setup
this._thumbnailUpdateTimer = new DispatcherTimer();
this._thumbnailUpdateTimer.Tick += ThumbnailUpdateTimerTick;
this._thumbnailUpdateTimer.Interval = new TimeSpan(0, 0, 0, 0, 500); // TODO Make it configurable
// TODO Move mayouts stuff out
_uniqueLayouts = new Dictionary<string, Dictionary<string, Point>>();
_flatLayout = new Dictionary<string, Point>();
_flatLayoutShortcuts = new Dictionary<string, string>();
_clientLayout = new Dictionary<string, WindowProperties>();
// TODO To be removed
_xmlBadToOkChars = new Dictionary<string, string>();
_xmlBadToOkChars["<"] = "---lt---";
_xmlBadToOkChars["&"] = "---amp---";
_xmlBadToOkChars[">"] = "---gt---";
_xmlBadToOkChars["\""] = "---quot---";
_xmlBadToOkChars["\'"] = "---apos---";
_xmlBadToOkChars[","] = "---comma---";
_xmlBadToOkChars["."] = "---dot---";
}
public event Action<IList<IThumbnailView>> ThumbnailsAdded;
public event Action<IList<IThumbnailView>> ThumbnailsUpdated;
public event Action<IList<IThumbnailView>> ThumbnailsRemoved;
public event Action<Size> ThumbnailSizeChanged;
public void Activate()
{
this.LoadLayout();
this._thumbnailUpdateTimer.Start();
this.RefreshThumbnails();
}
public void Deactivate()
{
this._thumbnailUpdateTimer.Stop();
}
public void SetThumbnailState(IntPtr thumbnailId, bool hideAlways)
{
IThumbnailView thumbnail;
if (!this._thumbnailViews.TryGetValue(thumbnailId, out thumbnail))
{
return;
}
thumbnail.IsEnabled = !hideAlways;
}
public void SetThumbnailsSize(Size size)
{
this._ignoreViewEvents = true;
foreach (KeyValuePair<IntPtr, IThumbnailView> entry in this._thumbnailViews)
{
entry.Value.Size = size;
entry.Value.Refresh();
}
this.ThumbnailSizeChanged?.Invoke(size);
this._ignoreViewEvents = false;
}
// TODO Drop dependency on the configuration object
public void RefreshThumbnails()
{
IntPtr foregroundWindowHandle = DwmApiNativeMethods.GetForegroundWindow();
Boolean hideAllThumbnails = (Properties.Settings.Default.hide_all && !this.IsClientWindowActive(foregroundWindowHandle)) || !DwmApiNativeMethods.DwmIsCompositionEnabled();
this._ignoreViewEvents = true;
// Hide, show, resize and move
foreach (KeyValuePair<IntPtr, IThumbnailView> entry in this._thumbnailViews)
{
IThumbnailView view = entry.Value;
if (hideAllThumbnails || !view.IsEnabled)
{
if (view.IsActive)
{
view.Hide();
}
continue;
}
if (view.Id == this._activeClientHandle && Properties.Settings.Default.hide_active)
{
if (view.IsActive)
{
view.Hide();
}
continue;
}
if (Properties.Settings.Default.unique_layout)
{
this.ApplyPerClientLayout(view, this._activeClientTitle);
}
else
{
this.ApplyFlatLayout(view);
}
view.IsOverlayEnabled = Properties.Settings.Default.show_overlay;
if (!this._isHoverEffectActive)
{
view.SetOpacity(Properties.Settings.Default.opacity);
}
if (!view.IsActive)
{
view.Show();
}
}
this._ignoreViewEvents = false;
}
public void SetupThumbnailFrames()
{
// TODO Drop config dependency
this._ignoreViewEvents = true;
foreach (KeyValuePair<IntPtr, IThumbnailView> entry in this._thumbnailViews)
{
entry.Value.SetWindowFrames(Properties.Settings.Default.show_thumb_frames);
}
this._ignoreViewEvents = false;
}
private void ThumbnailUpdateTimerTick(object sender, EventArgs e)
{
this.UpdateThumbnailsList();
this.RefreshThumbnails();
}
private Process[] GetClientProcesses()
{
return Process.GetProcessesByName(ThumbnailManager.ClientProcessName);
}
private void UpdateThumbnailsList()
{
Process[] clientProcesses = this.GetClientProcesses();
List<IntPtr> processHandles = new List<IntPtr>(clientProcesses.Length);
IntPtr foregroundWindowHandle = DwmApiNativeMethods.GetForegroundWindow();
List<IThumbnailView> viewsAdded = new List<IThumbnailView>();
List<IThumbnailView> viewsUpdated = new List<IThumbnailView>();
List<IThumbnailView> viewsRemoved = new List<IThumbnailView>();
foreach (Process process in clientProcesses)
{
IntPtr processHandle = process.MainWindowHandle;
string processTitle = process.MainWindowTitle;
processHandles.Add(processHandle);
IThumbnailView view;
this._thumbnailViews.TryGetValue(processHandle, out view);
if ((view == null) && (processTitle != ""))
{
Size thumbnailSize = new Size();
thumbnailSize.Width = (int)Properties.Settings.Default.sync_resize_x;
thumbnailSize.Height = (int)Properties.Settings.Default.sync_resize_y;
view = this._thumbnailViewFactory.Create(processHandle, ThumbnailManager.DefaultThumbnailTitle, thumbnailSize);
view.IsEnabled = true;
view.IsOverlayEnabled = Properties.Settings.Default.show_overlay;
view.SetTopMost(Properties.Settings.Default.always_on_top);
view.SetWindowFrames(Properties.Settings.Default.show_thumb_frames);
view.ThumbnailResized += ThumbnailViewResized;
view.ThumbnailMoved += ThumbnailViewMoved;
view.ThumbnailFocused += ThumbnailViewFocused;
view.ThumbnailLostFocus += ThumbnailViewLostFocus;
view.ThumbnailActivated += ThumbnailActivated;
this._thumbnailViews.Add(processHandle, view);
this.SetupClientWindow(processHandle, processTitle);
viewsAdded.Add(view);
}
else if ((view != null) && (processTitle != view.Title)) // update thumbnail title
{
view.Title = processTitle;
// TODO Shortcuts should be handled at manager level
//string value;
//if (_flatLayoutShortcuts.TryGetValue(processTitle, out value))
//{
// view.RegisterShortcut(value);
//}
this.SetupClientWindow(processHandle, processTitle);
viewsUpdated.Add(view);
}
if (process.MainWindowHandle == foregroundWindowHandle)
{
this._activeClientHandle = process.MainWindowHandle;
this._activeClientTitle = process.MainWindowTitle;
}
}
// Cleanup
IList<IntPtr> obsoleteThumbnails = new List<IntPtr>();
foreach (IntPtr processHandle in _thumbnailViews.Keys)
{
if (!processHandles.Contains(processHandle))
{
obsoleteThumbnails.Add(processHandle);
}
}
foreach (IntPtr processHandle in obsoleteThumbnails)
{
IThumbnailView view = this._thumbnailViews[processHandle];
_thumbnailViews.Remove(processHandle);
// TODO Remove hotkey here
view.ThumbnailResized -= ThumbnailViewResized;
view.ThumbnailMoved -= ThumbnailViewMoved;
view.ThumbnailFocused -= ThumbnailViewFocused;
view.ThumbnailLostFocus -= ThumbnailViewLostFocus;
view.ThumbnailActivated -= ThumbnailActivated;
view.Close();
viewsRemoved.Add(view);
}
this.ThumbnailsAdded?.Invoke(viewsAdded);
this.ThumbnailsUpdated?.Invoke(viewsUpdated);
this.ThumbnailsRemoved?.Invoke(viewsRemoved);
}
private void ThumbnailViewFocused(IntPtr id)
{
if (this._isHoverEffectActive)
{
return;
}
this._isHoverEffectActive = true;
IThumbnailView view = this._thumbnailViews[id];
this.ThumbnailZoomIn(view);
view.SetTopMost(true);
view.SetOpacity(1.0);
}
private void ThumbnailViewLostFocus(IntPtr id)
{
if (!this._isHoverEffectActive)
{
return;
}
IThumbnailView view = this._thumbnailViews[id];
this.ThumbnailZoomOut(view);
view.SetOpacity(Properties.Settings.Default.opacity);
this._isHoverEffectActive = false;
}
private void ThumbnailActivated(IntPtr id)
{
DwmApiNativeMethods.SetForegroundWindow(id);
int style = DwmApiNativeMethods.GetWindowLong(id, DwmApiNativeMethods.GWL_STYLE);
if ((style & DwmApiNativeMethods.WS_MINIMIZE) == DwmApiNativeMethods.WS_MINIMIZE)
{
DwmApiNativeMethods.ShowWindowAsync(id, DwmApiNativeMethods.SW_SHOWNORMAL);
}
this.UpdateClientLocation();
this.SaveLayout(); // Stores info about client window locations
foreach (KeyValuePair<IntPtr, IThumbnailView> entry in this._thumbnailViews)
{
IThumbnailView view = entry.Value;
view.SetTopMost(Properties.Settings.Default.always_on_top);
}
}
private void ThumbnailViewResized(IntPtr id)
{
if (this._ignoreViewEvents)
{
return;
}
IThumbnailView view = this._thumbnailViews[id];
this.SetThumbnailsSize(view.Size);
view.Refresh();
}
private void ThumbnailViewMoved(IntPtr id)
{
if (this._ignoreViewEvents)
{
return;
}
IThumbnailView view = this._thumbnailViews[id];
this.UpdateThumbnailPosition(view.Title, view.Location);
view.Refresh();
}
private void SetupClientWindow(IntPtr clientHandle, string clientTitle)
{
if (!Properties.Settings.Default.track_client_windows)
{
return;
}
WindowProperties windowProperties;
if (!this._clientLayout.TryGetValue(clientTitle, out windowProperties))
{
return;
}
DwmApiNativeMethods.MoveWindow(clientHandle, windowProperties.X, windowProperties.Y, windowProperties.Width, windowProperties.Height, true);
}
private bool IsClientWindowActive(IntPtr windowHandle)
{
foreach (KeyValuePair<IntPtr, IThumbnailView> entry in _thumbnailViews)
{
if (entry.Value.IsKnownHandle(windowHandle))
{
return true;
}
}
return false;
}
private void UpdateThumbnailPosition(string title, Point position)
{
if (Properties.Settings.Default.unique_layout)
{
Dictionary<string, Point> layout;
if (_uniqueLayouts.TryGetValue(_activeClientTitle, out layout))
{
layout[title] = position;
}
else if (_activeClientTitle == "")
{
_uniqueLayouts[_activeClientTitle] = new Dictionary<string, Point>();
_uniqueLayouts[_activeClientTitle][title] = position;
}
}
else
{
_flatLayout[title] = position;
}
}
private void ThumbnailZoomIn(IThumbnailView view)
{
// TODO Use global settings object
float zoomFactor = Properties.Settings.Default.zoom_amount;
this._thumbnailBaseSize = view.Size;
this._thumbnailBaseLocation = view.Location;
this._ignoreViewEvents = true;
view.Size = new Size((int)(zoomFactor * view.Size.Width), (int)(zoomFactor * view.Size.Height));
int locationX = view.Location.X;
int locationY = view.Location.Y;
int newWidth = view.Size.Width;
int newHeight = view.Size.Height;
int oldWidth = this._thumbnailBaseSize.Width;
int oldHeight = this._thumbnailBaseSize.Height;
// TODO Use global settings object
switch ((ZoomAnchor)Properties.Settings.Default.zoom_anchor)
{
case ZoomAnchor.NW:
break;
case ZoomAnchor.N:
view.Location = new Point(locationX - newWidth / 2 + oldWidth / 2, locationY);
break;
case ZoomAnchor.NE:
view.Location = new Point(locationX - newWidth + oldWidth, locationY);
break;
case ZoomAnchor.W:
view.Location = new Point(locationX, locationY - newHeight / 2 + oldHeight / 2);
break;
case ZoomAnchor.C:
view.Location = new Point(locationX - newWidth / 2 + oldWidth / 2, locationY - newHeight / 2 + oldHeight / 2);
break;
case ZoomAnchor.E:
view.Location = new Point(locationX - newWidth + oldWidth, locationY - newHeight / 2 + oldHeight / 2);
break;
case ZoomAnchor.SW:
view.Location = new Point(locationX, locationY - newHeight + this._thumbnailBaseSize.Height);
break;
case ZoomAnchor.S:
view.Location = new Point(locationX - newWidth / 2 + oldWidth / 2, locationY - newHeight + oldHeight);
break;
case ZoomAnchor.SE:
view.Location = new Point(locationX - newWidth + oldWidth, locationY - newHeight + oldHeight);
break;
}
view.Refresh();
this._ignoreViewEvents = false;
}
private void ThumbnailZoomOut(IThumbnailView view)
{
this._ignoreViewEvents = true;
view.Size = this._thumbnailBaseSize;
view.Location = this._thumbnailBaseLocation;
view.Refresh();
this._ignoreViewEvents = false;
}
// ************************************************************************
// ************************************************************************
// ************************************************************************
// ************************************************************************
// ************************************************************************
// ************************************************************************
// TODO Reenable this method
private void UpdateClientLocation()
{
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);
WindowProperties location = new WindowProperties();
location.X = rect.Left;
location.Y = rect.Top;
location.Width = client_width;
location.Height = client_height;
_clientLayout[process.MainWindowTitle] = location;
}
}
// TODO Layouting and stuff should be renewed later
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 LoadLayout()
{
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())
{
WindowProperties location = new WindowProperties();
location.X = Convert.ToInt32(el.Element("x").Value);
location.Y = Convert.ToInt32(el.Element("y").Value);
location.Width = Convert.ToInt32(el.Element("width").Value);
location.Height = Convert.ToInt32(el.Element("height").Value);
_clientLayout[ParseXElement(el)] = location;
}
}
}
private void SaveLayout()
{
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 ApplyPerClientLayout(IThumbnailView 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.Title, out new_loc))
{
thumbnailWindow.Location = new_loc;
}
else
{
// create inner dict
layout[thumbnailWindow.Title] = thumbnailWindow.Location;
}
}
else if (last_known_active_window != "")
{
// create outer dict
_uniqueLayouts[last_known_active_window] = new Dictionary<string, Point>();
_uniqueLayouts[last_known_active_window][thumbnailWindow.Title] = thumbnailWindow.Location;
}
}
private void ApplyFlatLayout(IThumbnailView thumbnailWindow)
{
Point layout;
if (_flatLayout.TryGetValue(thumbnailWindow.Title, out layout))
{
thumbnailWindow.Location = layout;
}
else if (thumbnailWindow.Title != "")
{
_flatLayout[thumbnailWindow.Title] = thumbnailWindow.Location;
}
}
}
}

View File

@@ -19,12 +19,13 @@ namespace EveOPreview
// UI classes // UI classes
IApplicationController controller = new ApplicationController(container) IApplicationController controller = new ApplicationController(container)
.RegisterView<IMainView, MainForm>() .RegisterView<IMainView, MainForm>()
.RegisterView<IThumbnailView, ThumbnailView>()
.RegisterView<IThumbnailDescriptionView, ThumbnailDescriptionView>() .RegisterView<IThumbnailDescriptionView, ThumbnailDescriptionView>()
.RegisterInstance(new ApplicationContext()); .RegisterInstance(new ApplicationContext());
// Application services // Application services
controller.RegisterService<EveOPreview.Thumbnails.IThumbnailFactory, EveOPreview.Thumbnails.ThumbnailFactory>() controller.RegisterService<IThumbnailManager, ThumbnailManager>()
.RegisterService<EveOPreview.Thumbnails.IThumbnailManager, EveOPreview.Thumbnails.ThumbnailManager>() .RegisterService<IThumbnailViewFactory, ThumbnailViewFactory>()
.RegisterService<IThumbnailDescriptionViewFactory, ThumbnailDescriptionViewFactory>(); .RegisterService<IThumbnailDescriptionViewFactory, ThumbnailDescriptionViewFactory>();
controller.Run<EveOPreview.UI.MainPresenter>(); controller.Run<EveOPreview.UI.MainPresenter>();

View File

@@ -1,13 +0,0 @@
using System;
using System.Drawing;
namespace EveOPreview.Thumbnails
{
public class ThumbnailFactory : IThumbnailFactory
{
public IThumbnail Create(IThumbnailManager manager, IntPtr sourceWindow, string title, Size size)
{
return new ThumbnailWindow(manager, sourceWindow, title, size);
}
}
}

View File

@@ -1,507 +0,0 @@
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.Thumbnails
{
public class ThumbnailManager : IThumbnailManager
{
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;
public ThumbnailManager(IThumbnailFactory factory)
{
_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 event Action<IList<IThumbnail>> ThumbnailsAdded;
public event Action<IList<IThumbnail>> ThumbnailsUpdated;
public event Action<IList<IThumbnail>> ThumbnailsRemoved;
public event Action<Size> ThumbnailSizeChanged;
public void Activate()
{
this.load_layout();
this._dispatcherTimer.Start();
this.RefreshThumbnails();
}
public void Deactivate()
{
this._dispatcherTimer.Stop();
}
public void SetThumbnailState(IntPtr thumbnailId, bool hideAlways)
{
IThumbnail thumbnail;
if (!this._previews.TryGetValue(thumbnailId, out thumbnail))
{
return;
}
thumbnail.IsPreviewEnabled = !hideAlways;
}
private void spawn_and_kill_previews()
{
// TODO Extract this!
Process[] processes = Process.GetProcessesByName("ExeFile");
List<IntPtr> processHandles = new List<IntPtr>();
List<IThumbnail> addedList = new List<IThumbnail>();
List<IThumbnail> updatedList = new List<IThumbnail>();
List<IThumbnail> removedList = new List<IThumbnail>();
// 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]);
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);
}
updatedList.Add(_previews[process.MainWindowHandle]);
refresh_client_window_locations(process);
}
if (process.MainWindowHandle == DwmApiNativeMethods.GetForegroundWindow())
{
_activeClientHandle = process.MainWindowHandle;
_activeClientTitle = process.MainWindowTitle;
}
}
// TODO Check for null list
this.ThumbnailsAdded?.Invoke(addedList);
this.ThumbnailsUpdated?.Invoke(updatedList);
// 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]);
_previews[processHandle].CloseThumbnail();
_previews.Remove(processHandle);
}
// TODO Check for null list
this.ThumbnailsRemoved?.Invoke(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();
RefreshThumbnails();
if (_ignoringSizeSync.ElapsedMilliseconds > 500) { _ignoringSizeSync.Stop(); };
}
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 size)
{
if (Properties.Settings.Default.sync_resize && _ignoringSizeSync.ElapsedMilliseconds > 500)
{
_ignoringSizeSync.Stop();
this.ThumbnailSizeChanged?.Invoke(size);
foreach (KeyValuePair<IntPtr, IThumbnail> entry in _previews)
{
if (entry.Value.IsPreviewHandle(DwmApiNativeMethods.GetForegroundWindow()))
{
entry.Value.SetSize(size);
}
}
}
}
public void RefreshThumbnails()
{
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);
}
}
public void SetupThumbnailFrames()
{
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);
}
}
public void UpdatePreviewPosition(string title, Point position)
{
if (Properties.Settings.Default.unique_layout)
{
Dictionary<string, Point> layout;
if (_uniqueLayouts.TryGetValue(_activeClientTitle, out layout))
{
layout[title] = position;
}
else if (_activeClientTitle == "")
{
_uniqueLayouts[_activeClientTitle] = new Dictionary<string, Point>();
_uniqueLayouts[_activeClientTitle][title] = position;
}
}
else
{
_flatLayout[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;
}
}
}

View File

@@ -1,444 +0,0 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using EveOPreview.Configuration;
using EveOPreview.UI;
namespace EveOPreview.Thumbnails
{
public partial class ThumbnailWindow : Form, IThumbnail
{
#region Private fields
private readonly bool _isInitializing;
private readonly IntPtr _sourceWindow;
private readonly IThumbnailManager _manager;
private readonly ThumbnailOverlay _overlay;
private Hotkey _hotkey; // This field stores the hotkey reference
private Size _baseSize;
private Point _basePosition;
private bool _isThumbnailSetUp;
private DWM_THUMBNAIL_PROPERTIES _Thumbnail;
private IntPtr _ThumbnailHandle;
private bool _ignoreMouseOverEvent;
private bool _isHoverEffectActive;
private bool _isZoomActive;
#endregion
// This constructor should never be used directly
public ThumbnailWindow(IThumbnailManager manager, IntPtr sourceWindow, string title, Size size)
{
this._isInitializing = true;
this.IsPreviewEnabled = true;
this.IsOverlayEnabled = true;
this._sourceWindow = sourceWindow;
this._manager = manager;
this._isThumbnailSetUp = false;
this._ignoreMouseOverEvent = false;
this._isHoverEffectActive = false;
this._isZoomActive = false;
InitializeComponent();
this.Text = title;
this._overlay = new ThumbnailOverlay(this.Preview_Click);
this._isInitializing = false;
this.SetSize(size);
}
public IntPtr Id
{
get
{
return this._sourceWindow;
}
}
public bool IsZoomEnabled { get; set; }
public bool IsPreviewEnabled { get; set; }
public bool IsOverlayEnabled { get; set; }
public bool IsPreviewHandle(IntPtr handle)
{
return (this.Handle == handle) || (this._overlay.Handle == handle);
}
public void ShowThumbnail()
{
if (this.IsPreviewEnabled)
{
this.Show();
if (this.IsOverlayEnabled)
{
this._overlay.Show();
this.MakeOverlayTopMost();
}
else
{
this._overlay.Hide();
}
}
else
{
this.HideThumbnail();
}
}
public void HideThumbnail()
{
this.Hide();
this._overlay.Hide();
}
public void CloseThumbnail()
{
this._overlay.Close();
this.Close();
}
public void SetLabel(string label)
{
this.Text = label;
this._overlay.SetOverlayLabel(label);
}
public string GetLabel()
{
return this.Text;
}
public void SetSize(Size size)
{
this.Size = size;
this._baseSize = this.Size;
this._basePosition = this.Location;
}
public void SetLocation(Point location)
{
if (!(this._isInitializing || this._ignoreMouseOverEvent))
{
this.Location = location;
}
this.RefreshPreview();
}
public Point GetLocation()
{
return this.Location;
}
public void SetOpacity(double opacity)
{
if (this._isHoverEffectActive)
{
return;
}
this.Opacity = opacity;
}
public void RegisterShortcut(string shortcut)
{
if (String.IsNullOrEmpty(shortcut))
{
return;
}
KeysConverter converter = new KeysConverter();
object keysObject = converter.ConvertFrom(shortcut);
if (keysObject == null)
{
return;
}
Keys key = (Keys)keysObject;
Hotkey hotkey = new Hotkey();
if ((key & Keys.Shift) == Keys.Shift)
{
hotkey.Shift = true;
}
if ((key & Keys.Alt) == Keys.Alt)
{
hotkey.Alt = true;
}
if ((key & Keys.Control) == Keys.Control)
{
hotkey.Control = true;
}
key = key & ~Keys.Shift & ~Keys.Alt & ~Keys.Control;
hotkey.KeyCode = key;
hotkey.Pressed += Hotkey_Pressed;
hotkey.Register(this);
this._hotkey = hotkey;
}
public void SetTopMost(bool topmost)
{
if (!this.IsPreviewEnabled)
{
return;
}
this.TopMost = topmost;
this.MakeOverlayTopMost();
}
public void SetWindowFrames(bool enable)
{
this.FormBorderStyle = enable ? FormBorderStyle.SizableToolWindow : FormBorderStyle.None;
}
protected override CreateParams CreateParams
{
get
{
var Params = base.CreateParams;
Params.ExStyle |= (int)DwmApiNativeMethods.WS_EX_TOOLWINDOW;
return Params;
}
}
private void Preview_MouseHover(object sender, EventArgs e)
{
if (!this._ignoreMouseOverEvent)
{
this._ignoreMouseOverEvent = true;
if (this.IsZoomEnabled)
{
this.ZoomIn();
}
this.SetTopMost(true);
}
this.Opacity = 1.0f;
this._isHoverEffectActive = true;
this.RefreshPreview();
}
private void Preview_MouseLeave(object sender, EventArgs e)
{
if (this._ignoreMouseOverEvent)
{
if (this.IsZoomEnabled)
{
this.ZoomOut();
}
this._ignoreMouseOverEvent = false;
}
this._isHoverEffectActive = false;
this.Opacity = Properties.Settings.Default.opacity; // TODO Use local object
this.RefreshPreview();
}
private void Preview_Click(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
this.ActivateClient();
this._manager.NotifyPreviewSwitch();
}
if (e.Button == MouseButtons.Right)
{
// do smth cool?
}
if (e.Button == MouseButtons.Middle)
{
// do smth cool?
}
}
private void Hotkey_Pressed(Object sender, EventArgs e)
{
this.ActivateClient();
this._manager.NotifyPreviewSwitch();
}
protected override void OnResize(EventArgs e)
{
this.RefreshPreview();
base.OnResize(e);
if (!(this._isInitializing || this._ignoreMouseOverEvent))
{
this._manager.SyncPreviewSize(this.Size);
}
}
protected override void OnMove(EventArgs e)
{
base.OnMove(e);
if (!(this._isInitializing || this._ignoreMouseOverEvent))
{
this._manager.UpdatePreviewPosition(this.Text, this.Location);
}
this.RefreshPreview();
}
private void MakeOverlayTopMost()
{
this._overlay.TopMost = true;
}
private void RefreshPreview()
{
if (this._isInitializing)
{
return;
}
if (DwmApiNativeMethods.DwmIsCompositionEnabled())
{
if (this._isThumbnailSetUp == false)
{
this.SetUpThumbnail();
}
this._Thumbnail.rcDestination = new RECT(0, 0, this.ClientRectangle.Right, this.ClientRectangle.Bottom);
DwmApiNativeMethods.DwmUpdateThumbnailProperties(this._ThumbnailHandle, this._Thumbnail);
}
else
{
this._isThumbnailSetUp = false;
}
Size overlaySize = this.RenderAreaPictureBox.Size;
overlaySize.Width -= 2 * 5;
overlaySize.Height -= 2 * 5;
Point overlayLocation = this.Location;
overlayLocation.X += 5 + (this.Size.Width - this.RenderAreaPictureBox.Size.Width) / 2;
overlayLocation.Y += 5 + (this.Size.Height - this.RenderAreaPictureBox.Size.Height) - (this.Size.Width - this.RenderAreaPictureBox.Size.Width) / 2;
this._overlay.Size = overlaySize;
this._overlay.Location = overlayLocation;
}
private void SetUpThumbnail()
{
if (this._isThumbnailSetUp || !DwmApiNativeMethods.DwmIsCompositionEnabled())
{
return;
}
this._ThumbnailHandle = DwmApiNativeMethods.DwmRegisterThumbnail(this.Handle, this._sourceWindow);
this._Thumbnail = new DWM_THUMBNAIL_PROPERTIES();
this._Thumbnail.dwFlags = DWM_TNP_CONSTANTS.DWM_TNP_VISIBLE
+ DWM_TNP_CONSTANTS.DWM_TNP_OPACITY
+ DWM_TNP_CONSTANTS.DWM_TNP_RECTDESTINATION
+ DWM_TNP_CONSTANTS.DWM_TNP_SOURCECLIENTAREAONLY;
this._Thumbnail.opacity = 255;
this._Thumbnail.fVisible = true;
this._Thumbnail.fSourceClientAreaOnly = true;
this._isThumbnailSetUp = true;
}
private void ZoomIn()
{
if (this._isZoomActive)
{
return;
}
this._isZoomActive = true;
// TODO Use global settings object
float zoomFactor = Properties.Settings.Default.zoom_amount;
this._baseSize = this.Size;
this._basePosition = this.Location;
this.Size = new Size((int)(zoomFactor * this.Size.Width), (int)(zoomFactor * this.Size.Height));
// TODO Use global settings object
switch ((ZoomAnchor)Properties.Settings.Default.zoom_anchor)
{
case ZoomAnchor.NW:
break;
case ZoomAnchor.N:
this.Location = new Point(this.Location.X - this.Size.Width / 2 + this._baseSize.Width / 2, this.Location.Y);
break;
case ZoomAnchor.NE:
this.Location = new Point(this.Location.X - this.Size.Width + this._baseSize.Width, this.Location.Y);
break;
case ZoomAnchor.W:
this.Location = new Point(this.Location.X, this.Location.Y - this.Size.Height / 2 + this._baseSize.Height / 2);
break;
case ZoomAnchor.C:
this.Location = new Point(this.Location.X - this.Size.Width / 2 + this._baseSize.Width / 2, this.Location.Y - this.Size.Height / 2 + this._baseSize.Height / 2);
break;
case ZoomAnchor.E:
this.Location = new Point(this.Location.X - this.Size.Width + this._baseSize.Width, this.Location.Y - this.Size.Height / 2 + this._baseSize.Height / 2);
break;
case ZoomAnchor.SW:
this.Location = new Point(this.Location.X, this.Location.Y - this.Size.Height + this._baseSize.Height);
break;
case ZoomAnchor.S:
this.Location = new Point(this.Location.X - this.Size.Width / 2 + this._baseSize.Width / 2, this.Location.Y - this.Size.Height + this._baseSize.Height);
break;
case ZoomAnchor.SE:
this.Location = new Point(this.Location.X - this.Size.Width + this._baseSize.Width, this.Location.Y - this.Size.Height + this._baseSize.Height);
break;
}
}
private void ZoomOut()
{
if (!this._isZoomActive)
{
return;
}
this.Size = this._baseSize;
this.Location = this._basePosition;
this._isZoomActive = false;
}
private void ActivateClient()
{
DwmApiNativeMethods.SetForegroundWindow(this._sourceWindow);
int style = DwmApiNativeMethods.GetWindowLong(this._sourceWindow, DwmApiNativeMethods.GWL_STYLE);
if ((style & DwmApiNativeMethods.WS_MAXIMIZE) == DwmApiNativeMethods.WS_MAXIMIZE)
{
// Client is already maximized, no action is required
}
else if ((style & DwmApiNativeMethods.WS_MINIMIZE) == DwmApiNativeMethods.WS_MINIMIZE)
{
DwmApiNativeMethods.ShowWindowAsync(this._sourceWindow, DwmApiNativeMethods.SW_SHOWNORMAL);
}
}
}
}

View File

@@ -1,34 +0,0 @@
using System;
using System.Drawing;
namespace EveOPreview.Thumbnails
{
public interface IThumbnail
{
IntPtr Id { get; }
bool IsZoomEnabled { get; set; }
bool IsPreviewEnabled { get; set; }
bool IsOverlayEnabled { get; set; }
bool IsPreviewHandle(IntPtr handle);
void ShowThumbnail();
void HideThumbnail();
void CloseThumbnail();
void RegisterShortcut(string shortcut);
// TODO Turn this into a property
void SetLabel(string label);
string GetLabel();
void SetLocation(Point location);
Point GetLocation();
void SetOpacity(double opacity);
void SetTopMost(bool topmost);
void SetWindowFrames(bool enable);
void SetSize(Size size);
}
}

View File

@@ -1,10 +0,0 @@
using System;
using System.Drawing;
namespace EveOPreview.Thumbnails
{
public interface IThumbnailFactory
{
IThumbnail Create(IThumbnailManager manager, IntPtr sourceWindow, string title, Size size);
}
}

View File

@@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
namespace EveOPreview.Thumbnails
{
public interface IThumbnailManager
{
void Activate();
void NotifyPreviewSwitch();
void SetThumbnailState(IntPtr thumbnailId, bool hideAlways);
void SyncPreviewSize(Size size);
void UpdatePreviewPosition(string title, Point position);
void RefreshThumbnails();
void SetupThumbnailFrames();
event Action<IList<IThumbnail>> ThumbnailsAdded;
event Action<IList<IThumbnail>> ThumbnailsUpdated;
event Action<IList<IThumbnail>> ThumbnailsRemoved;
event Action<Size> ThumbnailSizeChanged;
}
}

View File

@@ -11,12 +11,13 @@ namespace EveOPreview.UI
this._controller = controller; this._controller = controller;
} }
public IThumbnailDescriptionView Create(IntPtr id, string title) public IThumbnailDescriptionView Create(IntPtr id, string title, bool isDisabled)
{ {
IThumbnailDescriptionView view = this._controller.Create<IThumbnailDescriptionView>(); IThumbnailDescriptionView view = this._controller.Create<IThumbnailDescriptionView>();
view.Id = id; view.Id = id;
view.Title = title; view.Title = title;
view.IsDisabled = isDisabled;
return view; return view;
} }

View File

@@ -0,0 +1,26 @@
using System;
using System.Drawing;
namespace EveOPreview.UI
{
public class ThumbnailViewFactory : IThumbnailViewFactory
{
private readonly IApplicationController _controller;
public ThumbnailViewFactory(IApplicationController controller)
{
this._controller = controller;
}
public IThumbnailView Create(IntPtr id, string title, Size size)
{
IThumbnailView view = this._controller.Create<IThumbnailView>();
view.Id = id;
view.Title = title;
view.Size = size;
return view;
}
}
}

View File

@@ -2,9 +2,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
using System.Globalization;
using EveOPreview.Configuration;
using EveOPreview.Thumbnails;
namespace EveOPreview.UI namespace EveOPreview.UI
{ {
@@ -312,7 +309,7 @@ namespace EveOPreview.UI
public event Action<ViewCloseRequest> FormCloseRequested; public event Action<ViewCloseRequest> FormCloseRequested;
public event Action ApplicationSettingsChanged; public event Action ApplicationSettingsChanged;
public event Action ThumbnailsSizeChanged; public event Action ThumbnailsSizeChanged;
public event Action<IntPtr, Boolean> ThumbnailStateChanged; public event Action<IntPtr> ThumbnailStateChanged;
public event Action ForumUrlLinkActivated; public event Action ForumUrlLinkActivated;
#region UI events #region UI events
@@ -343,8 +340,9 @@ namespace EveOPreview.UI
{ {
return; return;
} }
selectedItem.IsDisabled = (e.NewValue == CheckState.Checked);
this.ThumbnailStateChanged?.Invoke(selectedItem.Id, e.NewValue == CheckState.Checked); this.ThumbnailStateChanged?.Invoke(selectedItem.Id);
} }
private void ForumLinkLabelClicked_Handler(object sender, LinkLabelLinkClickedEventArgs e) private void ForumLinkLabelClicked_Handler(object sender, LinkLabelLinkClickedEventArgs e)

View File

@@ -8,6 +8,8 @@ namespace EveOPreview.UI
public string Title { get; set; } public string Title { get; set; }
public bool IsDisabled { get; set; }
public void Show() public void Show()
{ {
} }

View File

@@ -1,33 +1,33 @@
namespace EveOPreview.Thumbnails namespace EveOPreview.UI
{ {
partial class ThumbnailOverlay partial class ThumbnailOverlay
{ {
/// <summary> /// <summary>
/// Required designer variable. /// Required designer variable.
/// </summary> /// </summary>
private System.ComponentModel.IContainer components = null; private System.ComponentModel.IContainer components = null;
/// <summary> /// <summary>
/// Clean up any resources being used. /// Clean up any resources being used.
/// </summary> /// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if (disposing && (components != null)) if (disposing && (components != null))
{ {
components.Dispose(); components.Dispose();
} }
base.Dispose(disposing); base.Dispose(disposing);
} }
#region Windows Form Designer generated code #region Windows Form Designer generated code
/// <summary> /// <summary>
/// Required method for Designer support - do not modify /// Required method for Designer support - do not modify
/// the contents of this method with the code editor. /// the contents of this method with the code editor.
/// </summary> /// </summary>
private void InitializeComponent() private void InitializeComponent()
{ {
System.Windows.Forms.PictureBox OverlayAreaPictureBox; System.Windows.Forms.PictureBox OverlayAreaPictureBox;
this.OverlayLabel = new System.Windows.Forms.Label(); this.OverlayLabel = new System.Windows.Forms.Label();
OverlayAreaPictureBox = new System.Windows.Forms.PictureBox(); OverlayAreaPictureBox = new System.Windows.Forms.PictureBox();
@@ -81,7 +81,7 @@
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout(); this.PerformLayout();
} }
#endregion #endregion

View File

@@ -1,7 +1,7 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
namespace EveOPreview.Thumbnails namespace EveOPreview.UI
{ {
public partial class ThumbnailOverlay : Form public partial class ThumbnailOverlay : Form
{ {

View File

@@ -1,6 +1,6 @@
namespace EveOPreview.Thumbnails namespace EveOPreview.UI
{ {
partial class ThumbnailWindow partial class ThumbnailView
{ {
/// <summary> /// <summary>
/// Required designer variable. /// Required designer variable.
@@ -31,11 +31,11 @@ namespace EveOPreview.Thumbnails
this.RenderAreaPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; this.RenderAreaPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.RenderAreaPictureBox.TabIndex = 0; this.RenderAreaPictureBox.TabIndex = 0;
this.RenderAreaPictureBox.TabStop = false; this.RenderAreaPictureBox.TabStop = false;
this.RenderAreaPictureBox.MouseLeave += new System.EventHandler(this.Preview_MouseLeave); this.RenderAreaPictureBox.MouseLeave += new System.EventHandler(this.LostFocus_Handler);
this.RenderAreaPictureBox.MouseHover += new System.EventHandler(this.Preview_MouseHover); this.RenderAreaPictureBox.MouseHover += new System.EventHandler(this.Focused_Handler);
this.RenderAreaPictureBox.MouseUp += new System.Windows.Forms.MouseEventHandler(this.Preview_Click); this.RenderAreaPictureBox.MouseUp += new System.Windows.Forms.MouseEventHandler(this.ThumbnailActivated_Handler);
// //
// Preview // ThumbnailView
// //
this.AccessibleRole = System.Windows.Forms.AccessibleRole.None; this.AccessibleRole = System.Windows.Forms.AccessibleRole.None;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -47,12 +47,14 @@ namespace EveOPreview.Thumbnails
this.MaximizeBox = false; this.MaximizeBox = false;
this.MinimizeBox = false; this.MinimizeBox = false;
this.MinimumSize = new System.Drawing.Size(64, 64); this.MinimumSize = new System.Drawing.Size(64, 64);
this.Name = "ThumbnailWindow"; this.Name = "ThumbnailView";
this.Opacity = 0.1D; this.Opacity = 0.1D;
this.ShowIcon = false; this.ShowIcon = false;
this.ShowInTaskbar = false; this.ShowInTaskbar = false;
this.Text = "Preview"; this.Text = "Preview";
this.TopMost = true; this.TopMost = true;
this.Move += new System.EventHandler(this.Move_Handler);
this.Resize += new System.EventHandler(this.Resize_Handler);
((System.ComponentModel.ISupportInitialize)(this.RenderAreaPictureBox)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.RenderAreaPictureBox)).EndInit();
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout(); this.PerformLayout();

View File

@@ -0,0 +1,282 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace EveOPreview.UI
{
public partial class ThumbnailView : Form, IThumbnailView
{
#region Private fields
//private readonly IThumbnailManager _manager;
private readonly ThumbnailOverlay _overlay;
//private Size _baseSize;
//private Point _basePosition;
// This is pure brainless View
// Just somewhat more complex than usual
private bool _isThumbnailSetUp;
private DWM_THUMBNAIL_PROPERTIES _Thumbnail;
private IntPtr _ThumbnailHandle;
private int _currentWidth;
private int _currentHeight;
private int _currentTop;
private int _currentLeft;
#endregion
public ThumbnailView()
{
this.IsEnabled = true;
this.IsActive = false;
this.IsOverlayEnabled = false;
this._isThumbnailSetUp = false;
this._currentWidth = -1;
this._currentHeight = -1;
this._currentTop = -1;
this._currentLeft = -1;
InitializeComponent();
this._overlay = new ThumbnailOverlay(this.ThumbnailActivated_Handler);
}
public IntPtr Id { get; set; }
public string Title
{
get
{
return this.Text;
}
set
{
this.Text = value;
this._overlay.SetOverlayLabel(value);
}
}
public bool IsEnabled { get; set; }
public bool IsActive { get; set; }
public bool IsOverlayEnabled { get; set; }
public event Action<IntPtr> ThumbnailResized;
public event Action<IntPtr> ThumbnailMoved;
public event Action<IntPtr> ThumbnailFocused;
public event Action<IntPtr> ThumbnailLostFocus;
public event Action<IntPtr> ThumbnailActivated;
public new void Show()
{
base.Show();
if (this.IsOverlayEnabled)
{
this._overlay.Show();
this._overlay.TopMost = true;
}
else
{
this._overlay.Hide();
}
this.Refresh();
this.IsActive = true;
}
public new void Hide()
{
this.IsActive = false;
this._overlay.Hide();
base.Hide();
}
public new void Close()
{
this.IsActive = false;
this._overlay.Close();
base.Close();
}
// This method is used to determine if the provided Handle is related to client or its thumbnail
public bool IsKnownHandle(IntPtr handle)
{
return (this.Id == handle) || (this.Handle == handle) || (this._overlay.Handle == handle);
}
public void SetOpacity(double opacity)
{
this.Opacity = opacity;
}
public void SetWindowFrames(bool enable)
{
this.FormBorderStyle = enable ? FormBorderStyle.SizableToolWindow : FormBorderStyle.None;
}
public void SetTopMost(bool enableTopmost)
{
this.TopMost = enableTopmost;
this._overlay.TopMost = true;
}
public new void Refresh()
{
if (this._isThumbnailSetUp == false)
{
this.InitializeThumbnail();
}
bool sizeChanged = (this._currentWidth != this.ClientRectangle.Right) || (this._currentHeight != this.ClientRectangle.Bottom);
bool locationChanged = (this._currentLeft != this.Location.X) || (this._currentTop != this.Location.Y);
if (sizeChanged)
{
this._currentWidth = this.ClientRectangle.Right;
this._currentHeight = this.ClientRectangle.Bottom;
this._Thumbnail.rcDestination = new RECT(0, 0, this._currentWidth, this._currentHeight);
DwmApiNativeMethods.DwmUpdateThumbnailProperties(this._ThumbnailHandle, this._Thumbnail);
}
if (!(this.IsOverlayEnabled && (sizeChanged || locationChanged)))
{
return;
}
Size overlaySize = this.RenderAreaPictureBox.Size;
overlaySize.Width -= 2 * 5;
overlaySize.Height -= 2 * 5;
Point overlayLocation = this.Location;
this._currentLeft = overlayLocation.X;
this._currentTop = overlayLocation.Y;
overlayLocation.X += 5 + (this.Size.Width - this.RenderAreaPictureBox.Size.Width) / 2;
overlayLocation.Y += 5 + (this.Size.Height - this.RenderAreaPictureBox.Size.Height) - (this.Size.Width - this.RenderAreaPictureBox.Size.Width) / 2;
this._overlay.Size = overlaySize;
this._overlay.Location = overlayLocation;
}
#region GUI events
protected override CreateParams CreateParams
{
get
{
var Params = base.CreateParams;
Params.ExStyle |= (int)DwmApiNativeMethods.WS_EX_TOOLWINDOW;
return Params;
}
}
private void Move_Handler(object sender, EventArgs e)
{
this.ThumbnailMoved?.Invoke(this.Id);
}
private void Resize_Handler(object sender, EventArgs e)
{
this.ThumbnailResized?.Invoke(this.Id);
}
private void Focused_Handler(object sender, EventArgs e)
{
this.ThumbnailFocused?.Invoke(this.Id);
}
private void LostFocus_Handler(object sender, EventArgs e)
{
this.ThumbnailLostFocus?.Invoke(this.Id);
}
private void ThumbnailActivated_Handler(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
this.ThumbnailActivated?.Invoke(this.Id);
}
//if (e.Button == MouseButtons.Right)
//{
// // do smth cool?
//}
//if (e.Button == MouseButtons.Middle)
//{
// // do smth cool?
//}
}
#endregion
private void InitializeThumbnail()
{
this._ThumbnailHandle = DwmApiNativeMethods.DwmRegisterThumbnail(this.Handle, this.Id);
this._Thumbnail = new DWM_THUMBNAIL_PROPERTIES();
this._Thumbnail.dwFlags = DWM_TNP_CONSTANTS.DWM_TNP_VISIBLE
+ DWM_TNP_CONSTANTS.DWM_TNP_OPACITY
+ DWM_TNP_CONSTANTS.DWM_TNP_RECTDESTINATION
+ DWM_TNP_CONSTANTS.DWM_TNP_SOURCECLIENTAREAONLY;
this._Thumbnail.opacity = 255;
this._Thumbnail.fVisible = true;
this._Thumbnail.fSourceClientAreaOnly = true;
this._isThumbnailSetUp = true;
}
//private Hotkey _hotkey; // This field stores the hotkey reference
//public void RegisterShortcut(string shortcut)
//{
//if (String.IsNullOrEmpty(shortcut))
//{
// return;
//}
//KeysConverter converter = new KeysConverter();
//object keysObject = converter.ConvertFrom(shortcut);
//if (keysObject == null)
//{
// return;
//}
//Keys key = (Keys)keysObject;
//Hotkey hotkey = new Hotkey();
//if ((key & Keys.Shift) == Keys.Shift)
//{
// hotkey.Shift = true;
//}
//if ((key & Keys.Alt) == Keys.Alt)
//{
// hotkey.Alt = true;
//}
//if ((key & Keys.Control) == Keys.Control)
//{
// hotkey.Control = true;
//}
//key = key & ~Keys.Shift & ~Keys.Alt & ~Keys.Control;
//hotkey.KeyCode = key;
//hotkey.Pressed += Hotkey_Pressed;
//hotkey.Register(this);
//this._hotkey = hotkey;
//}
}
}

View File

@@ -46,7 +46,7 @@ namespace EveOPreview.UI
event Action<ViewCloseRequest> FormCloseRequested; event Action<ViewCloseRequest> FormCloseRequested;
event Action ApplicationSettingsChanged; event Action ApplicationSettingsChanged;
event Action ThumbnailsSizeChanged; event Action ThumbnailsSizeChanged;
event Action<IntPtr, Boolean> ThumbnailStateChanged; event Action<IntPtr> ThumbnailStateChanged;
event Action ForumUrlLinkActivated; event Action ForumUrlLinkActivated;
} }
} }

View File

@@ -6,5 +6,6 @@ namespace EveOPreview.UI
{ {
IntPtr Id { get; set; } IntPtr Id { get; set; }
string Title { get; set; } string Title { get; set; }
bool IsDisabled { get; set; }
} }
} }

View File

@@ -4,6 +4,6 @@ namespace EveOPreview.UI
{ {
public interface IThumbnailDescriptionViewFactory public interface IThumbnailDescriptionViewFactory
{ {
IThumbnailDescriptionView Create(IntPtr id, string title); IThumbnailDescriptionView Create(IntPtr id, string title, bool isDisabled);
} }
} }

View File

@@ -0,0 +1,31 @@
using System;
using System.Drawing;
namespace EveOPreview.UI
{
public interface IThumbnailView : IView
{
IntPtr Id { get; set; }
string Title { get; set; }
bool IsEnabled { get; set; }
bool IsActive { get; set; }
Point Location { get; set; }
Size Size { get; set; }
bool IsOverlayEnabled { get; set; }
bool IsKnownHandle(IntPtr handle);
void SetOpacity(double opacity);
void SetWindowFrames(bool enable);
void SetTopMost(bool enableTopmost);
void Refresh();
event Action<IntPtr> ThumbnailResized;
event Action<IntPtr> ThumbnailMoved;
event Action<IntPtr> ThumbnailFocused;
event Action<IntPtr> ThumbnailLostFocus;
event Action<IntPtr> ThumbnailActivated;
}
}

View File

@@ -0,0 +1,10 @@
using System;
using System.Drawing;
namespace EveOPreview.UI
{
public interface IThumbnailViewFactory
{
IThumbnailView Create(IntPtr id, string title, Size size);
}
}