mirror of
https://github.com/Hofknecht/SystemTrayMenu.git
synced 2024-09-30 09:06:32 +13:00
Improve async icon loading
Response time for an loaded icon should be faster as update no longer depends on timer Loading icon will now share image source prevents creation of lost of loading icon copies
This commit is contained in:
parent
f7fff25ba7
commit
13e7cedaa6
5 changed files with 105 additions and 101 deletions
|
@ -206,33 +206,22 @@ namespace SystemTrayMenu.DataClasses
|
|||
|
||||
internal void ReadIcon(bool updateIconInBackground)
|
||||
{
|
||||
bool loading;
|
||||
Icon? icon;
|
||||
bool cacheHit;
|
||||
|
||||
if (IsPointingToFolder)
|
||||
{
|
||||
icon = IconReader.GetFolderIconWithCache(Path, ShowOverlay, updateIconInBackground, Level == 0, out loading);
|
||||
cacheHit = IconReader.GetFolderIconWithCache(Path, ShowOverlay, updateIconInBackground, Level == 0, UpdateFinalIcon);
|
||||
}
|
||||
else
|
||||
{
|
||||
icon = IconReader.GetFileIconWithCache(Path, ResolvedPath, ShowOverlay, updateIconInBackground, Level == 0, out loading);
|
||||
cacheHit = IconReader.GetFileIconWithCache(Path, ResolvedPath, ShowOverlay, updateIconInBackground, Level == 0, UpdateFinalIcon);
|
||||
}
|
||||
|
||||
IconLoading = loading;
|
||||
if (!IconLoading)
|
||||
if (!cacheHit)
|
||||
{
|
||||
if (icon == null)
|
||||
{
|
||||
icon = Resources.NotFound;
|
||||
}
|
||||
else if (HiddenEntry)
|
||||
{
|
||||
icon = IconReader.AddIconOverlay(icon, Resources.White50Percentage);
|
||||
}
|
||||
IconLoading = true;
|
||||
ColumnIcon = SystemTrayMenu.Resources.StaticResources.LoadingImgSrc; // TODO: Maybe add rotation animation like for the loading Menu icon? (See: pictureBoxLoading, LoadingRotation)
|
||||
}
|
||||
|
||||
ColumnIcon = icon?.ToImageSource();
|
||||
ColumnIcon?.Freeze();
|
||||
}
|
||||
|
||||
internal void OpenItem(int clickCount)
|
||||
|
@ -350,5 +339,23 @@ namespace SystemTrayMenu.DataClasses
|
|||
BackgroundBrush = Brushes.White;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateFinalIcon(Icon? icon)
|
||||
{
|
||||
if (icon == null)
|
||||
{
|
||||
icon = Resources.NotFound;
|
||||
}
|
||||
else if (HiddenEntry)
|
||||
{
|
||||
icon = IconReader.AddIconOverlay(icon, Resources.White50Percentage);
|
||||
}
|
||||
|
||||
ImageSource? imgsrc = icon?.ToImageSource();
|
||||
imgsrc?.Freeze();
|
||||
|
||||
IconLoading = false;
|
||||
ColumnIcon = imgsrc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,39 @@
|
|||
// <copyright file="StaticResources.cs" company="PlaceholderCompany">
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace SystemTrayMenu.Resources
|
||||
{
|
||||
using System.Drawing;
|
||||
|
||||
public class StaticResources
|
||||
{
|
||||
public static readonly Icon LoadingIcon = Properties.Resources.Loading;
|
||||
}
|
||||
}
|
||||
// <copyright file="StaticResources.cs" company="PlaceholderCompany">
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace SystemTrayMenu.Resources
|
||||
{
|
||||
using System.Drawing;
|
||||
using System.Windows.Media;
|
||||
using SystemTrayMenu.Utilities;
|
||||
|
||||
internal class StaticResources
|
||||
{
|
||||
internal static readonly Icon LoadingIcon = Properties.Resources.Loading;
|
||||
|
||||
private static readonly object LoadingImgSrcLock = new ();
|
||||
|
||||
private static ImageSource? loadingImgSrc;
|
||||
|
||||
internal static ImageSource LoadingImgSrc
|
||||
{
|
||||
get
|
||||
{
|
||||
if (loadingImgSrc == null)
|
||||
{
|
||||
lock (LoadingImgSrcLock)
|
||||
{
|
||||
if (loadingImgSrc == null)
|
||||
{
|
||||
loadingImgSrc = Properties.Resources.Loading.ToImageSource();
|
||||
loadingImgSrc.Freeze(); // Make it accessible by any thread
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loadingImgSrc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
|
|||
|
||||
public class EventDelay
|
||||
{
|
||||
private readonly object checkLock = new();
|
||||
private readonly long waitTime;
|
||||
private long lastCheck;
|
||||
|
||||
|
@ -18,9 +19,7 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
|
|||
|
||||
public bool Check()
|
||||
{
|
||||
#pragma warning disable CA2002
|
||||
lock (this)
|
||||
#pragma warning restore CA2002
|
||||
lock (checkLock)
|
||||
{
|
||||
long now = DateTime.Now.Ticks;
|
||||
bool isPassed = now - lastCheck > waitTime;
|
||||
|
|
|
@ -37,7 +37,6 @@ namespace SystemTrayMenu.UserInterface
|
|||
private static readonly RoutedEvent FadeOutEvent = EventManager.RegisterRoutedEvent(
|
||||
nameof(FadeOut), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Menu));
|
||||
|
||||
private readonly DispatcherTimer timerUpdateIcons = new (DispatcherPriority.Background, Dispatcher.CurrentDispatcher);
|
||||
private readonly string folderPath;
|
||||
#if TODO // SEARCH
|
||||
public const string RowFilterShowAll = "[SortIndex] LIKE '%0%'";
|
||||
|
@ -116,7 +115,7 @@ namespace SystemTrayMenu.UserInterface
|
|||
labelStatus.Content = Translator.GetText("loading");
|
||||
|
||||
// Todo: use embedded resources that we can assign image in XAML already
|
||||
pictureBoxLoading.Source = SystemTrayMenu.Resources.StaticResources.LoadingIcon.ToImageSource();
|
||||
pictureBoxLoading.Source = SystemTrayMenu.Resources.StaticResources.LoadingImgSrc;
|
||||
pictureBoxLoading.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
|
@ -201,8 +200,6 @@ namespace SystemTrayMenu.UserInterface
|
|||
|
||||
Closed += (_, _) =>
|
||||
{
|
||||
timerUpdateIcons.Stop();
|
||||
|
||||
if (RowDataParent?.SubMenu == this)
|
||||
{
|
||||
RowDataParent.SubMenu = null;
|
||||
|
@ -213,8 +210,6 @@ namespace SystemTrayMenu.UserInterface
|
|||
item.SubMenu?.Close();
|
||||
}
|
||||
};
|
||||
|
||||
timerUpdateIcons.Tick += TimerUpdateIcons_Tick;
|
||||
}
|
||||
|
||||
internal event Action<RowData>? StartLoadSubMenu;
|
||||
|
@ -455,11 +450,6 @@ namespace SystemTrayMenu.UserInterface
|
|||
{
|
||||
SetSubMenuState(state.Value);
|
||||
}
|
||||
|
||||
if (startIconLoading)
|
||||
{
|
||||
timerUpdateIcons.Start();
|
||||
}
|
||||
}
|
||||
|
||||
internal void ActivateWithFade(bool recursive)
|
||||
|
@ -484,8 +474,6 @@ namespace SystemTrayMenu.UserInterface
|
|||
|
||||
internal void ShowWithFade(bool transparency, bool recursive)
|
||||
{
|
||||
timerUpdateIcons.Start();
|
||||
|
||||
if (recursive)
|
||||
{
|
||||
SubMenu?.ShowWithFade(transparency, true);
|
||||
|
@ -1129,27 +1117,6 @@ namespace SystemTrayMenu.UserInterface
|
|||
AppRestart.ByMenuButton();
|
||||
}
|
||||
|
||||
private void TimerUpdateIcons_Tick(object? sender, EventArgs e)
|
||||
{
|
||||
int iconsToUpdate = 0;
|
||||
|
||||
foreach (RowData rowData in dgv.Items)
|
||||
{
|
||||
rowData.RowIndex = dgv.Items.IndexOf(rowData);
|
||||
|
||||
if (rowData.IconLoading)
|
||||
{
|
||||
iconsToUpdate++;
|
||||
rowData.ReadIcon(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (iconsToUpdate < 1)
|
||||
{
|
||||
timerUpdateIcons.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void MainMenu_MoveStart(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
// Hide all sub menus to clear the view for repositioning of the main menu
|
||||
|
|
|
@ -54,17 +54,16 @@ namespace SystemTrayMenu.Utilities
|
|||
}
|
||||
}
|
||||
|
||||
public static Icon? GetFileIconWithCache(
|
||||
public static bool GetFileIconWithCache(
|
||||
string path,
|
||||
string resolvedPath,
|
||||
bool linkOverlay,
|
||||
bool updateIconInBackground,
|
||||
bool checkPersistentFirst,
|
||||
out bool loading)
|
||||
Action<Icon?> onIconLoaded)
|
||||
{
|
||||
loading = false;
|
||||
|
||||
Icon? icon = null;
|
||||
bool cacheHit;
|
||||
Icon? icon;
|
||||
string key;
|
||||
string extension = Path.GetExtension(path);
|
||||
if (IsExtensionWithSameIcon(extension))
|
||||
|
@ -79,8 +78,7 @@ namespace SystemTrayMenu.Utilities
|
|||
if (!DictIconCache(checkPersistentFirst).TryGetValue(key, out icon) &&
|
||||
!DictIconCache(!checkPersistentFirst).TryGetValue(key, out icon))
|
||||
{
|
||||
icon = Resources.StaticResources.LoadingIcon;
|
||||
loading = true;
|
||||
cacheHit = false;
|
||||
if (updateIconInBackground)
|
||||
{
|
||||
IconSize size = IconSize.Small;
|
||||
|
@ -94,30 +92,34 @@ namespace SystemTrayMenu.Utilities
|
|||
new Thread(UpdateIconInBackground).Start();
|
||||
void UpdateIconInBackground()
|
||||
{
|
||||
DictIconCache(checkPersistentFirst).GetOrAdd(key, GetIconSTA(path, resolvedPath, linkOverlay, size, false));
|
||||
Icon? icon = DictIconCache(checkPersistentFirst).GetOrAdd(key, GetIconSTA(path, resolvedPath, linkOverlay, size, false));
|
||||
onIconLoaded(icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheHit = true;
|
||||
onIconLoaded(icon);
|
||||
}
|
||||
|
||||
return icon;
|
||||
return cacheHit;
|
||||
}
|
||||
|
||||
public static Icon? GetFolderIconWithCache(
|
||||
public static bool GetFolderIconWithCache(
|
||||
string path,
|
||||
bool linkOverlay,
|
||||
bool updateIconInBackground,
|
||||
bool checkPersistentFirst,
|
||||
out bool loading)
|
||||
Action<Icon?> onIconLoaded)
|
||||
{
|
||||
loading = false;
|
||||
|
||||
Icon? icon = null;
|
||||
bool cacheHit;
|
||||
Icon? icon;
|
||||
string key = path;
|
||||
if (!DictIconCache(checkPersistentFirst).TryGetValue(key, out icon) &&
|
||||
!DictIconCache(!checkPersistentFirst).TryGetValue(key, out icon))
|
||||
{
|
||||
icon = Resources.StaticResources.LoadingIcon;
|
||||
loading = true;
|
||||
cacheHit = false;
|
||||
|
||||
if (updateIconInBackground)
|
||||
{
|
||||
|
@ -132,14 +134,17 @@ namespace SystemTrayMenu.Utilities
|
|||
|
||||
if (IsPreloading)
|
||||
{
|
||||
DictIconCache(checkPersistentFirst).GetOrAdd(key, GetFolder);
|
||||
cacheHit = true;
|
||||
icon = DictIconCache(checkPersistentFirst).GetOrAdd(key, GetFolder);
|
||||
onIconLoaded(icon);
|
||||
}
|
||||
else
|
||||
{
|
||||
new Thread(UpdateIconInBackground).Start();
|
||||
void UpdateIconInBackground()
|
||||
{
|
||||
DictIconCache(checkPersistentFirst).GetOrAdd(key, GetFolder);
|
||||
Icon? icon = DictIconCache(checkPersistentFirst).GetOrAdd(key, GetFolder);
|
||||
onIconLoaded(icon);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,8 +154,13 @@ namespace SystemTrayMenu.Utilities
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheHit = true;
|
||||
onIconLoaded(icon);
|
||||
}
|
||||
|
||||
return icon;
|
||||
return cacheHit;
|
||||
}
|
||||
|
||||
public static Icon? GetIconSTA(string path, string resolvedPath, bool linkOverlay, IconSize size, bool isFolder)
|
||||
|
@ -176,21 +186,16 @@ namespace SystemTrayMenu.Utilities
|
|||
return icon;
|
||||
}
|
||||
|
||||
public static Icon? AddIconOverlay(Icon? originalIcon, Icon overlay)
|
||||
public static Icon AddIconOverlay(Icon originalIcon, Icon overlay)
|
||||
{
|
||||
Icon? icon = originalIcon;
|
||||
if (originalIcon != null)
|
||||
{
|
||||
using Bitmap target = new(originalIcon.Width, originalIcon.Height, PixelFormat.Format32bppArgb);
|
||||
using Graphics graphics = Graphics.FromImage(target);
|
||||
graphics.DrawIcon(originalIcon, 0, 0);
|
||||
graphics.DrawIcon(overlay, new(0, 0, originalIcon.Width + 2, originalIcon.Height + 2));
|
||||
target.MakeTransparent(target.GetPixel(1, 1));
|
||||
IntPtr hIcon = target.GetHicon();
|
||||
icon = (Icon)Icon.FromHandle(hIcon).Clone();
|
||||
NativeMethods.User32DestroyIcon(hIcon);
|
||||
}
|
||||
|
||||
using Bitmap target = new(originalIcon.Width, originalIcon.Height, PixelFormat.Format32bppArgb);
|
||||
using Graphics graphics = Graphics.FromImage(target);
|
||||
graphics.DrawIcon(originalIcon, 0, 0);
|
||||
graphics.DrawIcon(overlay, new(0, 0, originalIcon.Width + 2, originalIcon.Height + 2));
|
||||
target.MakeTransparent(target.GetPixel(1, 1));
|
||||
IntPtr hIcon = target.GetHicon();
|
||||
Icon icon = (Icon)Icon.FromHandle(hIcon).Clone();
|
||||
NativeMethods.User32DestroyIcon(hIcon);
|
||||
return icon;
|
||||
}
|
||||
|
||||
|
@ -220,7 +225,7 @@ namespace SystemTrayMenu.Utilities
|
|||
Path.GetExtension(resolvedPath).Equals(".ico", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
icon = Icon.ExtractAssociatedIcon(resolvedPath);
|
||||
if (linkOverlay)
|
||||
if (linkOverlay && icon != null)
|
||||
{
|
||||
icon = AddIconOverlay(icon, Properties.Resources.LinkArrow);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue