├── ClaudiaIDE ├── Images │ └── .gitkeep ├── Localized │ └── .gitkeep ├── GuidList.cs ├── Properties │ └── AssemblyInfo.cs ├── source.extension.vsixmanifest ├── ClaudiaIDE.csproj └── Resources │ ├── ClaudiaIdePackage.zh-CN.vsct │ └── ClaudiaIdePackage.ja-JP.vsct ├── ClaudiaIDE16 ├── Images │ └── .gitkeep ├── Localized │ └── .gitkeep ├── GuidList.cs ├── Properties │ └── AssemblyInfo.cs ├── source.extension.vsixmanifest ├── ClaudiaIDE16.csproj └── Resources │ ├── ClaudiaIdePackage.zh-CN.vsct │ └── ClaudiaIdePackage.ja-JP.vsct ├── Images ├── tile01.png ├── tile02.png ├── tile03.png ├── tile04.png ├── howto01.png ├── howto02.png ├── howto03.png ├── howto04.png ├── example01.png ├── workaround01.png └── config-per-solution.png ├── .github └── FUNDING.yml ├── Shared ├── Resources │ ├── 400.ico │ ├── ss.png │ ├── vsixicon.png │ └── ClaudiaIDEMenu.png ├── Images │ ├── background.png │ └── background2.png ├── Interfaces │ ├── ISkipable.cs │ └── IPausable.cs ├── Helpers │ ├── AnimateImageChangeParams.cs │ ├── ResourceExtension.cs │ ├── DependencyObjectExtensions.cs │ ├── PausableTimer.cs │ ├── ImageDownloader.cs │ ├── ImageSourceAnimator.cs │ └── Utils.cs ├── GlobalSuppressions.cs ├── Shared.shproj ├── Settings │ ├── JsonSerializer.cs │ └── WeakEvent.cs ├── config.txt ├── ImageProviders │ ├── SingleImageWebProvider.cs │ ├── SingleImageProvider.cs │ ├── WebApiImageProvider.cs │ ├── SingleImageEachProvider.cs │ └── SlideShowImageProvider.cs ├── Extensions.cs ├── Localized │ └── LocalManager.cs ├── MenuCommands │ ├── ToggleHiddenImage.cs │ ├── OpenSettings.cs │ ├── ResetSolutionSettings.cs │ ├── AboutImage.cs │ ├── SaveSolutionSettings.cs │ ├── NextImage.cs │ └── PauseSlideshow.cs ├── Shared.projitems ├── ImageProvider.cs ├── VSPackage.Designer.cs ├── ClaudiaIDEFactory.cs └── VSPackage.resx ├── .editorconfig ├── .gitignore ├── ClaudiaIDE.sln └── README.md /ClaudiaIDE/Images/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ClaudiaIDE16/Images/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ClaudiaIDE/Localized/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ClaudiaIDE16/Localized/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Images/tile01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Images/tile01.png -------------------------------------------------------------------------------- /Images/tile02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Images/tile02.png -------------------------------------------------------------------------------- /Images/tile03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Images/tile03.png -------------------------------------------------------------------------------- /Images/tile04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Images/tile04.png -------------------------------------------------------------------------------- /Images/howto01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Images/howto01.png -------------------------------------------------------------------------------- /Images/howto02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Images/howto02.png -------------------------------------------------------------------------------- /Images/howto03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Images/howto03.png -------------------------------------------------------------------------------- /Images/howto04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Images/howto04.png -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [buchizo] 4 | -------------------------------------------------------------------------------- /Images/example01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Images/example01.png -------------------------------------------------------------------------------- /Images/workaround01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Images/workaround01.png -------------------------------------------------------------------------------- /Shared/Resources/400.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Shared/Resources/400.ico -------------------------------------------------------------------------------- /Shared/Resources/ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Shared/Resources/ss.png -------------------------------------------------------------------------------- /Shared/Images/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Shared/Images/background.png -------------------------------------------------------------------------------- /Shared/Images/background2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Shared/Images/background2.png -------------------------------------------------------------------------------- /Shared/Resources/vsixicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Shared/Resources/vsixicon.png -------------------------------------------------------------------------------- /Images/config-per-solution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Images/config-per-solution.png -------------------------------------------------------------------------------- /Shared/Resources/ClaudiaIDEMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buchizo/ClaudiaIDE/HEAD/Shared/Resources/ClaudiaIDEMenu.png -------------------------------------------------------------------------------- /Shared/Interfaces/ISkipable.cs: -------------------------------------------------------------------------------- 1 | namespace ClaudiaIDE.Interfaces 2 | { 3 | internal interface ISkipable 4 | { 5 | void Skip(); 6 | } 7 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.cs] 4 | charset = utf-8 5 | end_of_line = crlf 6 | indent_style = space 7 | trim_trailing_whitespace = true 8 | csharp_new_line_before_open_brace = all 9 | -------------------------------------------------------------------------------- /Shared/Interfaces/IPausable.cs: -------------------------------------------------------------------------------- 1 | namespace ClaudiaIDE.Interfaces 2 | { 3 | internal interface IPausable 4 | { 5 | bool IsPaused { get; } 6 | void Pause(); 7 | void Resume(); 8 | } 9 | } -------------------------------------------------------------------------------- /Shared/Helpers/AnimateImageChangeParams.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ClaudiaIDE.Helpers 4 | { 5 | internal class AnimateImageChangeParams 6 | { 7 | public double TargetOpacity { get; set; } = 0.35; 8 | public TimeSpan FadeTime { get; set; } = TimeSpan.FromSeconds(5); 9 | } 10 | } -------------------------------------------------------------------------------- /ClaudiaIDE/GuidList.cs: -------------------------------------------------------------------------------- 1 | namespace ClaudiaIDE 2 | { 3 | public static class GuidList 4 | { 5 | public const string PackageId = "7442ac19-889b-4699-a817-e6e054877ee3"; 6 | public const string GeneralOptionPageId = "ACCEFBB9-1547-4B84-BA0D-B92F937FA28C"; 7 | public const string OptionPageId = "441f0a76-1771-41c2-817c-81b8b03fb0e8"; 8 | public const string DarkThemeOptionPageId = "EEFB93BE-B731-4DAC-BF91-6AAD0548BCBD"; 9 | public const string MenuSetId = "f0ffaf7c-8feb-40d2-b898-1acfe50e1d6b"; 10 | } 11 | } -------------------------------------------------------------------------------- /ClaudiaIDE16/GuidList.cs: -------------------------------------------------------------------------------- 1 | namespace ClaudiaIDE 2 | { 3 | public static class GuidList 4 | { 5 | public const string PackageId = "9ab800ef-0cff-4893-bf16-57d58ff53456"; 6 | public const string GeneralOptionPageId = "91A270EA-27B4-4A3A-BB2D-CFBC2E882FE1"; 7 | public const string OptionPageId = "595e3c9f-2648-4225-99cb-7e6ed3b5c354"; 8 | public const string DarkThemeOptionPageId = "06D8DABA-0E13-4E13-9990-F0879EFC823B"; 9 | public const string MenuSetId = "74c31f05-fe81-450e-912d-da9fc31105ac"; 10 | } 11 | } -------------------------------------------------------------------------------- /Shared/Helpers/ResourceExtension.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | 4 | namespace Shared.Helpers 5 | { 6 | public static class ResourceExtension 7 | { 8 | private static ResourceManager Resources = new ResourceManager("ClaudiaIDE.Localized.ResLocalized", Assembly.GetExecutingAssembly()); 9 | 10 | public static string GetResourceString(string key) 11 | { 12 | try 13 | { 14 | return Resources.GetString(key) ?? ""; 15 | } 16 | catch 17 | { 18 | return ""; 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Shared/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. Project-level 3 | // suppressions either have no target or are given a specific target 4 | // and scoped to a namespace, type, member, etc. 5 | // 6 | // To add a suppression to this file, right-click the message in the 7 | // Error List, point to "Suppress Message(s)", and click "In Project 8 | // Suppression File". You do not need to add suppressions to this 9 | // file manually. 10 | 11 | using System.Diagnostics.CodeAnalysis; 12 | 13 | [assembly: SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")] -------------------------------------------------------------------------------- /Shared/Shared.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6d268f80-dd38-48bb-81e2-51805e5a4e17 5 | 14.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Shared/Settings/JsonSerializer.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using System.Runtime.Serialization.Json; 4 | using System.Text; 5 | 6 | namespace ClaudiaIDE.Settings 7 | { 8 | public static class JsonSerializer where TType : class 9 | { 10 | public static string Serialize(TType instance) 11 | { 12 | var serializer = new DataContractJsonSerializer(typeof(TType)); 13 | using (var stream = new MemoryStream()) 14 | using (var writer = JsonReaderWriterFactory.CreateJsonWriter(stream, Encoding.UTF8, true, true)) 15 | { 16 | serializer.WriteObject(writer, instance); 17 | writer.Flush(); 18 | return Encoding.UTF8.GetString(stream.ToArray(), 0, stream.ToArray().Count()); 19 | } 20 | } 21 | 22 | public static TType DeSerialize(string json) 23 | { 24 | using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) 25 | { 26 | var serializer = new DataContractJsonSerializer(typeof(TType)); 27 | return serializer.ReadObject(stream) as TType; 28 | } 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /Shared/config.txt: -------------------------------------------------------------------------------- 1 | { 2 | "BackgroundImageAbsolutePath":"Images\\background.png", 3 | "BackgroundImagesDirectoryAbsolutePath":"Images", 4 | "Extensions":".png, .jpg, .gif, .bmp", 5 | "ImageBackgroundType":0, 6 | "Opacity":0.35, 7 | "ImageStretch":0, 8 | "PositionHorizon":1, 9 | "PositionVertical":1, 10 | "UpdateImageInterval":"PT30M", 11 | "ImageFadeAnimationInterval":"PT30S", 12 | "LoopSlideshow":true, 13 | "ShuffleSlideshow":false, 14 | "MaxWidth": 0, 15 | "MaxHeight": 0, 16 | "SoftEdgeX": 0, 17 | "SoftEdgeY": 0, 18 | "BlurRadius": 0, 19 | "BlurMethod": 0, 20 | "ExpandToIDE": false, 21 | "ViewBoxPointX": 0, 22 | "ViewBoxPointY": 0, 23 | "IsLimitToMainlyEditorWindow": false, 24 | "ViewPortWidth": 1, 25 | "ViewPortHeight": 1, 26 | "ViewPortPointX": 0, 27 | "ViewPortPointY": 0, 28 | "TileMode": 0, 29 | "SingleWebUrl": "", 30 | "WebApiDownloadInterval": "PT10S", 31 | "WebApiEndpoint": "https://azure.moe/api/image", 32 | "WebApiJsonKey": "url", 33 | "WebSingleUrl": "https://azure.moe/img/topbackground.png", 34 | "IsTransparentToContentMargin": false, 35 | "IsTransparentToStickyScroll": false, 36 | "StickyScrollColor": "#00000000", 37 | "EditorBackgroundColor": "" 38 | } 39 | -------------------------------------------------------------------------------- /ClaudiaIDE/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Resources; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("ClaudiaIDE")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("ClaudiaIDE")] 14 | [assembly: AssemblyCopyright("")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: CLSCompliant(false)] 18 | [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 19 | 20 | // Setting ComVisible to false makes the types in this assembly not visible 21 | // to COM components. If you need to access a type in this assembly from 22 | // COM, set the ComVisible attribute to true on that type. 23 | [assembly: ComVisible(false)] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /ClaudiaIDE16/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Resources; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("ClaudiaIDE")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("ClaudiaIDE")] 14 | [assembly: AssemblyCopyright("")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: CLSCompliant(false)] 18 | [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 19 | 20 | // Setting ComVisible to false makes the types in this assembly not visible 21 | // to COM components. If you need to access a type in this assembly from 22 | // COM, set the ComVisible attribute to true on that type. 23 | [assembly: ComVisible(false)] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /Shared/Helpers/DependencyObjectExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Windows; 5 | using System.Windows.Media; 6 | 7 | namespace ClaudiaIDE.Helpers 8 | { 9 | public static class DependencyObjectExtensions 10 | { 11 | public static IEnumerable Children(this DependencyObject obj) 12 | { 13 | if (obj == null) 14 | throw new ArgumentNullException("obj"); 15 | 16 | var count = VisualTreeHelper.GetChildrenCount(obj); 17 | if (count == 0) 18 | yield break; 19 | 20 | for (var i = 0; i < count; i++) 21 | { 22 | var child = VisualTreeHelper.GetChild(obj, i); 23 | if (child != null) 24 | yield return child; 25 | } 26 | } 27 | 28 | public static IEnumerable Descendants(this DependencyObject obj) 29 | { 30 | if (obj == null) 31 | throw new ArgumentNullException("obj"); 32 | 33 | foreach (var child in obj.Children()) 34 | { 35 | yield return child; 36 | foreach (var grandChild in child.Descendants()) 37 | yield return grandChild; 38 | } 39 | } 40 | 41 | public static IEnumerable Children(this DependencyObject obj) 42 | where T : DependencyObject 43 | { 44 | return obj.Children().OfType(); 45 | } 46 | 47 | public static IEnumerable Descendants(this DependencyObject obj) 48 | where T : DependencyObject 49 | { 50 | return obj.Descendants().OfType(); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /Shared/Helpers/PausableTimer.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Timers; 3 | 4 | namespace ClaudiaIDE.Helpers 5 | { 6 | internal class PausableTimer : Timer 7 | { 8 | private readonly double _initialInterval; 9 | private readonly Stopwatch _stopwatch; 10 | private bool _resumed; 11 | 12 | public PausableTimer(double interval) : base(interval <= 0 ? 1 : interval) 13 | { 14 | _initialInterval = interval <= 0 ? 1 : interval; 15 | Elapsed += OnElapsed; 16 | IsPaused = false; 17 | _stopwatch = new Stopwatch(); 18 | } 19 | 20 | public double RemainingAfterPause { get; private set; } 21 | public bool IsPaused { get; private set; } 22 | 23 | public new void Start() 24 | { 25 | ResetStopwatch(); 26 | IsPaused = false; 27 | base.Start(); 28 | } 29 | 30 | public void Restart() 31 | { 32 | Stop(); 33 | Start(); 34 | } 35 | 36 | private void OnElapsed(object sender, ElapsedEventArgs elapsedEventArgs) 37 | { 38 | if (_resumed) 39 | { 40 | _resumed = false; 41 | Stop(); 42 | Interval = _initialInterval; 43 | Start(); 44 | } 45 | 46 | ResetStopwatch(); 47 | } 48 | 49 | private void ResetStopwatch() 50 | { 51 | _stopwatch.Reset(); 52 | _stopwatch.Start(); 53 | } 54 | 55 | public void Pause() 56 | { 57 | Stop(); 58 | IsPaused = true; 59 | _stopwatch.Stop(); 60 | RemainingAfterPause = Interval - _stopwatch.Elapsed.TotalMilliseconds; 61 | } 62 | 63 | public void Resume() 64 | { 65 | IsPaused = false; 66 | _resumed = true; 67 | Interval = RemainingAfterPause; 68 | RemainingAfterPause = 0; 69 | Start(); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Oo]bj/ 3 | 4 | # mstest test results 5 | TestResults 6 | 7 | ## Ignore Visual Studio temporary files, build results, and 8 | ## files generated by popular Visual Studio add-ons. 9 | 10 | # User-specific files 11 | *.suo 12 | *.user 13 | *.sln.docstates 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Rr]elease/ 18 | x64/ 19 | *_i.c 20 | *_p.c 21 | *.ilk 22 | *.meta 23 | *.obj 24 | *.pch 25 | *.pdb 26 | *.pgc 27 | *.pgd 28 | *.rsp 29 | *.sbr 30 | *.tlb 31 | *.tli 32 | *.tlh 33 | *.tmp 34 | *.log 35 | *.vspscc 36 | *.vssscc 37 | .builds 38 | 39 | # Visual C++ cache files 40 | ipch/ 41 | *.aps 42 | *.ncb 43 | *.opensdf 44 | *.sdf 45 | 46 | # Visual Studio profiler 47 | *.psess 48 | *.vsp 49 | *.vspx 50 | 51 | # Guidance Automation Toolkit 52 | *.gpState 53 | 54 | # ReSharper is a .NET coding add-in 55 | _ReSharper* 56 | 57 | # NCrunch 58 | *.ncrunch* 59 | .*crunch*.local.xml 60 | 61 | # Installshield output folder 62 | [Ee]xpress 63 | 64 | # DocProject is a documentation generator add-in 65 | DocProject/buildhelp/ 66 | DocProject/Help/*.HxT 67 | DocProject/Help/*.HxC 68 | DocProject/Help/*.hhc 69 | DocProject/Help/*.hhk 70 | DocProject/Help/*.hhp 71 | DocProject/Help/Html2 72 | DocProject/Help/html 73 | 74 | # Click-Once directory 75 | publish 76 | 77 | # Publish Web Output 78 | *.Publish.xml 79 | 80 | # NuGet Packages Directory 81 | packages 82 | 83 | # Windows Azure Build Output 84 | csx 85 | *.build.csdef 86 | 87 | # Windows Store app package directory 88 | AppPackages/ 89 | 90 | # Others 91 | [Oo]bj 92 | sql 93 | TestResults 94 | [Tt]est[Rr]esult* 95 | *.Cache 96 | ClientBin 97 | [Ss]tyle[Cc]op.* 98 | ~$* 99 | *.dbmdl 100 | Generated_Code #added for RIA/Silverlight projects 101 | 102 | # Backup & report files from converting an old project file to a newer 103 | # Visual Studio version. Backup files are not needed, because we have git ;-) 104 | _UpgradeReport_Files/ 105 | Backup*/ 106 | UpgradeLog*.XML 107 | 108 | .vs/ 109 | -------------------------------------------------------------------------------- /ClaudiaIDE16/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ClaudiaIDE 2019 6 | This extension allows you to change the background image of the editor. 7 | https://github.com/buchizo/ClaudiaIDE 8 | https://github.com/buchizo/ClaudiaIDE/wiki/Release-notes 9 | Resources\vsixicon.png 10 | Resources\ss.png 11 | theme, Text Editor, 痛IDE拡張, Background, Claudia 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Shared/ImageProviders/SingleImageWebProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Media.Imaging; 6 | using ClaudiaIDE.Helpers; 7 | using ClaudiaIDE.Settings; 8 | using Microsoft.VisualStudio.Threading; 9 | 10 | namespace ClaudiaIDE.ImageProviders 11 | { 12 | internal class SingleImageWebProvider : ImageProvider 13 | { 14 | private string _currentUrl; 15 | 16 | public SingleImageWebProvider(Setting setting, string solutionfile = null) : base(setting, solutionfile, 17 | ImageBackgroundType.WebSingle) 18 | { 19 | } 20 | 21 | protected override void OnSettingChanged(object sender, EventArgs e) 22 | { 23 | if ((sender as Setting)?.ImageBackgroundType != ImageBackgroundType.WebSingle) return; 24 | ImageDownloader.ResetUrl(); 25 | Image = null; 26 | } 27 | 28 | public override BitmapSource GetBitmap() 29 | { 30 | if (Image != null) return Image; 31 | LoadImageFromWebAsync().Forget(); 32 | return null; 33 | } 34 | 35 | private async Task LoadImageFromWebAsync() 36 | { 37 | try 38 | { 39 | _currentUrl = Setting.WebSingleUrl; 40 | if (!IsStaticImage()) return; 41 | Image = await ImageDownloader.LoadImageAsync(Setting.WebSingleUrl, Setting.ImageStretch, Setting.MaxWidth, Setting.MaxHeight, Setting); 42 | if (Image != null) FireImageAvailable(); 43 | } 44 | catch { } 45 | } 46 | 47 | public override bool IsStaticImage() 48 | { 49 | if (string.IsNullOrEmpty(_currentUrl)) return true; 50 | var f = new FileInfo(new Uri(_currentUrl).LocalPath); 51 | return !Setting.SupportVideoFileExtensions.Any(x => x == f.Extension.ToLower()); 52 | } 53 | 54 | public override string GetCurrentImageUri() 55 | { 56 | return _currentUrl; 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /Shared/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using EnvDTE; 5 | using EnvDTE80; 6 | using Microsoft.VisualStudio.Shell; 7 | 8 | namespace ClaudiaIDE 9 | { 10 | public static class Extensions 11 | { 12 | public static void Shuffle(this IList list) 13 | { 14 | var rng = new Random(); 15 | var n = list.Count; 16 | while (n > 1) 17 | { 18 | n--; 19 | var k = rng.Next(n + 1); 20 | var value = list[k]; 21 | list[k] = list[n]; 22 | list[n] = value; 23 | } 24 | } 25 | } 26 | 27 | public static class VisualStudioUtility 28 | { 29 | public static string GetSolutionSettingsFileFullPath(bool checkExists = true) 30 | { 31 | try 32 | { 33 | if (!TryGetSolutionPath(out string path)) return null; 34 | 35 | // CMake or other directory project (not .sln) `path` is directory 36 | var dir = File.GetAttributes(path).HasFlag(FileAttributes.Directory) 37 | ? path 38 | : Path.GetDirectoryName(path); 39 | if (string.IsNullOrWhiteSpace(dir)) return null; 40 | 41 | var configPath = Path.Combine(dir, ".claudiaideconfig"); 42 | return checkExists 43 | ? File.Exists(configPath) ? configPath : null 44 | : configPath; 45 | } 46 | catch 47 | { 48 | return null; 49 | } 50 | } 51 | 52 | 53 | public static bool TryGetSolutionPath(out string path) 54 | { 55 | try 56 | { 57 | var dte = Package.GetGlobalService(typeof(DTE)) as DTE2; 58 | path = dte?.Solution?.FileName; 59 | return !string.IsNullOrWhiteSpace(path); 60 | } 61 | catch 62 | { 63 | path = null; 64 | return false; 65 | } 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /ClaudiaIDE.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.28803.452 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClaudiaIDE", "ClaudiaIDE\ClaudiaIDE.csproj", "{FA0103C8-8CCD-4A1E-AF09-9862C9A4A04A}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{72CB9490-9766-43FD-8A16-11E9797EC02B}" 9 | ProjectSection(SolutionItems) = preProject 10 | .editorconfig = .editorconfig 11 | EndProjectSection 12 | EndProject 13 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Shared", "Shared\Shared.shproj", "{6D268F80-DD38-48BB-81E2-51805E5A4E17}" 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClaudiaIDE16", "ClaudiaIDE16\ClaudiaIDE16.csproj", "{E803B36C-090C-4155-B13C-EAE30CA78AA7}" 16 | EndProject 17 | Global 18 | GlobalSection(SharedMSBuildProjectFiles) = preSolution 19 | Shared\Shared.projitems*{6d268f80-dd38-48bb-81e2-51805e5a4e17}*SharedItemsImports = 13 20 | Shared\Shared.projitems*{e803b36c-090c-4155-b13c-eae30ca78aa7}*SharedItemsImports = 4 21 | Shared\Shared.projitems*{fa0103c8-8ccd-4a1e-af09-9862c9a4a04a}*SharedItemsImports = 4 22 | EndGlobalSection 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 24 | Debug|Any CPU = Debug|Any CPU 25 | Release|Any CPU = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {FA0103C8-8CCD-4A1E-AF09-9862C9A4A04A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {FA0103C8-8CCD-4A1E-AF09-9862C9A4A04A}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {FA0103C8-8CCD-4A1E-AF09-9862C9A4A04A}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {FA0103C8-8CCD-4A1E-AF09-9862C9A4A04A}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {E803B36C-090C-4155-B13C-EAE30CA78AA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {E803B36C-090C-4155-B13C-EAE30CA78AA7}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {E803B36C-090C-4155-B13C-EAE30CA78AA7}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {E803B36C-090C-4155-B13C-EAE30CA78AA7}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {742C5C24-8743-44F4-8877-60779C1E23B4} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /Shared/Localized/LocalManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Resources; 4 | 5 | namespace ClaudiaIDE.Localized 6 | { 7 | internal class LocalManager 8 | { 9 | internal static ResourceManager _rm; 10 | 11 | private static ResourceManager GetInstance() 12 | { 13 | if (_rm == null) _rm = ResLocalized.ResourceManager; 14 | 15 | return _rm; 16 | } 17 | 18 | [AttributeUsage(AttributeTargets.Assembly | 19 | AttributeTargets.Module | 20 | AttributeTargets.Class | 21 | AttributeTargets.Struct | 22 | AttributeTargets.Enum | 23 | AttributeTargets.Constructor | 24 | AttributeTargets.Method | 25 | AttributeTargets.Property | 26 | AttributeTargets.Field | 27 | AttributeTargets.Event | 28 | AttributeTargets.Interface | 29 | AttributeTargets.Parameter | 30 | AttributeTargets.Delegate | 31 | AttributeTargets.ReturnValue | 32 | AttributeTargets.GenericParameter)] 33 | internal class LocalizedDescriptionAttribute : DescriptionAttribute 34 | { 35 | internal LocalizedDescriptionAttribute(string _key) : base(Localize(_key)) 36 | { 37 | } 38 | 39 | private static string Localize(string _key) 40 | { 41 | return GetInstance().GetString(_key); 42 | } 43 | } 44 | 45 | [AttributeUsage(AttributeTargets.All)] 46 | internal class LocalizedCategoryAttribute : CategoryAttribute 47 | { 48 | internal LocalizedCategoryAttribute(string _key) : base(Localize(_key)) 49 | { 50 | } 51 | 52 | private static string Localize(string _key) 53 | { 54 | return GetInstance().GetString(_key); 55 | } 56 | } 57 | 58 | [AttributeUsage(AttributeTargets.Class | 59 | AttributeTargets.Method | 60 | AttributeTargets.Property | 61 | AttributeTargets.Event)] 62 | internal class LocalizedDisplayNameAttribute : DisplayNameAttribute 63 | { 64 | internal LocalizedDisplayNameAttribute(string _key) : base(Localize(_key)) 65 | { 66 | } 67 | 68 | private static string Localize(string _key) 69 | { 70 | return GetInstance().GetString(_key); 71 | } 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /Shared/MenuCommands/ToggleHiddenImage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Design; 3 | using ClaudiaIDE.Settings; 4 | using Microsoft.VisualStudio.Shell; 5 | using Task = System.Threading.Tasks.Task; 6 | 7 | namespace ClaudiaIDE.MenuCommands 8 | { 9 | /// 10 | /// Command handler 11 | /// 12 | internal sealed class ToggleHiddenImage 13 | { 14 | /// 15 | /// Command ID. 16 | /// 17 | public const int CommandId = 0x0140; 18 | 19 | /// 20 | /// Command menu group (command set GUID). 21 | /// 22 | public static readonly Guid CommandSet = new Guid(GuidList.MenuSetId); 23 | 24 | private readonly MenuCommand _menuItem; 25 | 26 | private ToggleHiddenImage(AsyncPackage package, OleMenuCommandService commandService) 27 | { 28 | commandService = commandService ?? throw new ArgumentNullException(nameof(commandService)); 29 | var menuCommandID = new CommandID(CommandSet, CommandId); 30 | _menuItem = new MenuCommand(Execute, menuCommandID) 31 | { 32 | Enabled = true 33 | }; 34 | commandService.AddCommand(_menuItem); 35 | } 36 | 37 | /// 38 | /// Gets the instance of the command. 39 | /// 40 | public static ToggleHiddenImage Instance { get; private set; } 41 | 42 | /// 43 | /// Initializes the singleton instance of the command. 44 | /// 45 | /// Owner package, not null. 46 | public static async Task InitializeAsync(AsyncPackage package) 47 | { 48 | // Switch to the main thread - the call to AddCommand in NextImage's constructor requires 49 | // the UI thread. 50 | if (Instance != null) return; 51 | await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken); 52 | var commandService = 53 | await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService; 54 | Instance = new ToggleHiddenImage(package, commandService); 55 | } 56 | 57 | /// 58 | /// This function is the callback used to execute the command when the menu item is clicked. 59 | /// See the constructor to see how the menu item is associated with this function using 60 | /// OleMenuCommandService service and MenuCommand class. 61 | /// 62 | /// Event sender. 63 | /// Event args. 64 | private void Execute(object sender, EventArgs e) 65 | { 66 | Setting.Instance.OnToggleVisibility(); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /Shared/MenuCommands/OpenSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Design; 3 | using ClaudiaIDE.Options; 4 | using Microsoft.VisualStudio.Shell; 5 | using Task = System.Threading.Tasks.Task; 6 | 7 | namespace ClaudiaIDE.MenuCommands 8 | { 9 | /// 10 | /// Command handler 11 | /// 12 | internal sealed class OpenSettings 13 | { 14 | /// 15 | /// Command ID. 16 | /// 17 | public const int CommandId = 0x0170; 18 | 19 | /// 20 | /// Command menu group (command set GUID). 21 | /// 22 | public static readonly Guid CommandSet = new Guid(GuidList.MenuSetId); 23 | 24 | private readonly MenuCommand _menuItem; 25 | private readonly AsyncPackage _package; 26 | 27 | private OpenSettings(AsyncPackage package, OleMenuCommandService commandService) 28 | { 29 | commandService = commandService ?? throw new ArgumentNullException(nameof(commandService)); 30 | var menuCommandID = new CommandID(CommandSet, CommandId); 31 | _package = package; 32 | _menuItem = new MenuCommand(Execute, menuCommandID) 33 | { 34 | Enabled = true 35 | }; 36 | commandService.AddCommand(_menuItem); 37 | } 38 | 39 | /// 40 | /// Gets the instance of the command. 41 | /// 42 | public static OpenSettings Instance { get; private set; } 43 | 44 | /// 45 | /// Initializes the singleton instance of the command. 46 | /// 47 | /// Owner package, not null. 48 | public static async Task InitializeAsync(AsyncPackage package) 49 | { 50 | // Switch to the main thread - the call to AddCommand in OpenSettings's constructor requires 51 | // the UI thread. 52 | if (Instance != null) return; 53 | await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken); 54 | var commandService = 55 | await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService; 56 | Instance = new OpenSettings(package, commandService); 57 | } 58 | 59 | /// 60 | /// This function is the callback used to execute the command when the menu item is clicked. 61 | /// See the constructor to see how the menu item is associated with this function using 62 | /// OleMenuCommandService service and MenuCommand class. 63 | /// 64 | /// Event sender. 65 | /// Event args. 66 | private void Execute(object sender, EventArgs e) 67 | { 68 | Instance._package?.ShowOptionPage(typeof(ClaudiaIdeGeneralOptionPageGrid)); 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /ClaudiaIDE/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ClaudiaIDE 6 | This extension allows you to change the background image of the editor. 7 | https://github.com/buchizo/ClaudiaIDE 8 | https://github.com/buchizo/ClaudiaIDE/wiki/Release-notes 9 | Resources\vsixicon.png 10 | Resources\ss.png 11 | theme, Text Editor, 痛IDE拡張, Background, Claudia 12 | 13 | 14 | 15 | amd64 16 | 17 | 18 | amd64 19 | 20 | 21 | amd64 22 | 23 | 24 | amd64 25 | 26 | 27 | arm64 28 | 29 | 30 | arm64 31 | 32 | 33 | arm64 34 | 35 | 36 | arm64 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Shared/Shared.projitems: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | 6d268f80-dd38-48bb-81e2-51805e5a4e17 7 | 8 | 9 | Shared 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Shared/MenuCommands/ResetSolutionSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Design; 3 | using System.IO; 4 | using ClaudiaIDE.Settings; 5 | using Microsoft.VisualStudio.Shell; 6 | using Task = System.Threading.Tasks.Task; 7 | 8 | namespace ClaudiaIDE.MenuCommands 9 | { 10 | /// 11 | /// Command handler 12 | /// 13 | internal sealed class ResetSolutionSettings 14 | { 15 | /// 16 | /// Command ID. 17 | /// 18 | public const int CommandId = 0x0150; 19 | 20 | /// 21 | /// Command menu group (command set GUID). 22 | /// 23 | public static readonly Guid CommandSet = new Guid(GuidList.MenuSetId); 24 | 25 | private readonly OleMenuCommand _menuItem; 26 | 27 | private readonly Setting _setting; 28 | 29 | private ResetSolutionSettings(AsyncPackage package, OleMenuCommandService commandService, Setting setting) 30 | { 31 | _setting = setting; 32 | commandService = commandService ?? throw new ArgumentNullException(nameof(commandService)); 33 | var menuCommandID = new CommandID(CommandSet, CommandId); 34 | _menuItem = new OleMenuCommand(Execute, menuCommandID); 35 | _menuItem.BeforeQueryStatus += (s, e) => 36 | { 37 | ThreadHelper.ThrowIfNotOnUIThread(); 38 | _menuItem.Enabled = !string.IsNullOrWhiteSpace(VisualStudioUtility.GetSolutionSettingsFileFullPath()); 39 | }; 40 | commandService.AddCommand(_menuItem); 41 | } 42 | 43 | /// 44 | /// Gets the instance of the command. 45 | /// 46 | public static ResetSolutionSettings Instance { get; private set; } 47 | 48 | /// 49 | /// Initializes the singleton instance of the command. 50 | /// 51 | /// Owner package, not null. 52 | public static async Task InitializeAsync(AsyncPackage package, Setting setting) 53 | { 54 | // Switch to the main thread - the call to AddCommand in NextImage's constructor requires 55 | // the UI thread. 56 | if (Instance != null) return; 57 | await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken); 58 | var commandService = 59 | await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService; 60 | Instance = new ResetSolutionSettings(package, commandService, setting); 61 | } 62 | 63 | /// 64 | /// Reset/remove .claudiaideconfig file from solution directory. 65 | /// 66 | /// 67 | /// 68 | private void Execute(object sender, EventArgs e) 69 | { 70 | ThreadHelper.ThrowIfNotOnUIThread(); 71 | var solution = VisualStudioUtility.GetSolutionSettingsFileFullPath(); 72 | if (string.IsNullOrWhiteSpace(solution)) return; 73 | try 74 | { 75 | File.Delete(solution); 76 | _setting.SolutionConfigFilePath = null; 77 | Setting.Instance.OnApplyChanged(); 78 | } 79 | catch { } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /Shared/MenuCommands/AboutImage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Design; 3 | using ClaudiaIDE.Forms; 4 | using ClaudiaIDE.ImageProviders; 5 | using Microsoft.VisualStudio.Shell; 6 | using Task = System.Threading.Tasks.Task; 7 | 8 | namespace ClaudiaIDE.MenuCommands 9 | { 10 | /// 11 | /// Command handler 12 | /// 13 | internal sealed class AboutImage 14 | { 15 | /// 16 | /// Command ID. 17 | /// 18 | public const int CommandId = 0x0160; 19 | 20 | /// 21 | /// Command menu group (command set GUID). 22 | /// 23 | public static readonly Guid CommandSet = new Guid(GuidList.MenuSetId); 24 | 25 | private readonly OleMenuCommand _menuItem; 26 | private readonly AsyncPackage _package; 27 | 28 | private AboutImage(AsyncPackage package, OleMenuCommandService commandService) 29 | { 30 | commandService = commandService ?? throw new ArgumentNullException(nameof(commandService)); 31 | var menuCommandID = new CommandID(CommandSet, CommandId); 32 | _package = package; 33 | _menuItem = new OleMenuCommand(Execute, menuCommandID); 34 | _menuItem.BeforeQueryStatus += (s, e) => 35 | { 36 | ImageProvider provider = ProvidersHolder.Instance.ActiveProvider; 37 | // It is unavailable with the SingleEach image type as the provider does not track the image within each individual pane. 38 | _menuItem.Enabled = !(provider is SingleImageEachProvider); 39 | }; 40 | commandService.AddCommand(_menuItem); 41 | } 42 | 43 | /// 44 | /// Gets the instance of the command. 45 | /// 46 | public static AboutImage Instance { get; private set; } 47 | 48 | /// 49 | /// Initializes the singleton instance of the command. 50 | /// 51 | /// Owner package, not null. 52 | public static async Task InitializeAsync(AsyncPackage package) 53 | { 54 | // Switch to the main thread - the call to AddCommand in AboutImage's constructor requires 55 | // the UI thread. 56 | if (Instance != null) return; 57 | await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken); 58 | var commandService = 59 | await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService; 60 | Instance = new AboutImage(package, commandService); 61 | } 62 | 63 | /// 64 | /// This function is the callback used to execute the command when the menu item is clicked. 65 | /// See the constructor to see how the menu item is associated with this function using 66 | /// OleMenuCommandService service and MenuCommand class. 67 | /// 68 | /// Event sender. 69 | /// Event args. 70 | private void Execute(object sender, EventArgs e) 71 | { 72 | ImageProvider provider = ProvidersHolder.Instance.ActiveProvider; 73 | if (provider == null) return; 74 | 75 | using (AboutImageForm form = new AboutImageForm(provider)) 76 | { 77 | form.ShowDialog(); 78 | } 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /Shared/MenuCommands/SaveSolutionSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Design; 3 | using ClaudiaIDE.Settings; 4 | using Microsoft.VisualStudio.Shell; 5 | using Task = System.Threading.Tasks.Task; 6 | 7 | namespace ClaudiaIDE.MenuCommands 8 | { 9 | /// 10 | /// Command handler 11 | /// 12 | internal sealed class SaveSolutionSettings 13 | { 14 | /// 15 | /// Command ID. 16 | /// 17 | public const int CommandId = 0x0130; 18 | 19 | /// 20 | /// Command menu group (command set GUID). 21 | /// 22 | public static readonly Guid CommandSet = new Guid(GuidList.MenuSetId); 23 | 24 | private readonly OleMenuCommand _menuItem; 25 | 26 | private readonly Setting _setting; 27 | 28 | private SaveSolutionSettings(AsyncPackage package, OleMenuCommandService commandService, Setting setting) 29 | { 30 | _setting = setting; 31 | commandService = commandService ?? throw new ArgumentNullException(nameof(commandService)); 32 | var menuCommandID = new CommandID(CommandSet, CommandId); 33 | _menuItem = new OleMenuCommand(Execute, menuCommandID); 34 | _menuItem.BeforeQueryStatus += (s, e) => 35 | { 36 | ThreadHelper.ThrowIfNotOnUIThread(); 37 | _menuItem.Enabled = VisualStudioUtility.TryGetSolutionPath(out _); 38 | }; 39 | commandService.AddCommand(_menuItem); 40 | } 41 | 42 | /// 43 | /// Gets the instance of the command. 44 | /// 45 | public static SaveSolutionSettings Instance { get; private set; } 46 | 47 | /// 48 | /// Initializes the singleton instance of the command. 49 | /// 50 | /// Owner package, not null. 51 | public static async Task InitializeAsync(AsyncPackage package, Setting setting) 52 | { 53 | // Switch to the main thread - the call to AddCommand in NextImage's constructor requires 54 | // the UI thread. 55 | if (Instance != null) return; 56 | await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken); 57 | var commandService = 58 | await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService; 59 | Instance = new SaveSolutionSettings(package, commandService, setting); 60 | } 61 | 62 | /// 63 | /// This function is the callback used to execute the command when the menu item is clicked. 64 | /// See the constructor to see how the menu item is associated with this function using 65 | /// OleMenuCommandService service and MenuCommand class. 66 | /// 67 | /// Event sender. 68 | /// Event args. 69 | private void Execute(object sender, EventArgs e) 70 | { 71 | ThreadHelper.ThrowIfNotOnUIThread(); 72 | var solution = VisualStudioUtility.GetSolutionSettingsFileFullPath(false); 73 | if (!string.IsNullOrWhiteSpace(solution)) 74 | { 75 | try { 76 | _setting.Serialize(solution); 77 | } 78 | catch { } 79 | } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /Shared/MenuCommands/NextImage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Design; 3 | using ClaudiaIDE.Interfaces; 4 | using Microsoft.VisualStudio.Shell; 5 | using Task = System.Threading.Tasks.Task; 6 | 7 | namespace ClaudiaIDE.MenuCommands 8 | { 9 | /// 10 | /// Command handler 11 | /// 12 | internal sealed class NextImage 13 | { 14 | /// 15 | /// Command ID. 16 | /// 17 | public const int CommandId = 0x0100; 18 | 19 | /// 20 | /// Command menu group (command set GUID). 21 | /// 22 | public static readonly Guid CommandSet = new Guid(GuidList.MenuSetId); 23 | 24 | private readonly OleMenuCommand _menuItem; 25 | 26 | 27 | private ISkipable activeSkipabe; 28 | 29 | /// 30 | /// Initializes a new instance of the class. 31 | /// Adds our command handlers for menu (commands must exist in the command table file) 32 | /// 33 | /// Owner package, not null. 34 | /// Command service to add command to, not null. 35 | private NextImage(AsyncPackage package, OleMenuCommandService commandService) 36 | { 37 | commandService = commandService ?? throw new ArgumentNullException(nameof(commandService)); 38 | var menuCommandID = new CommandID(CommandSet, CommandId); 39 | _menuItem = new OleMenuCommand(Execute, menuCommandID); 40 | _menuItem.BeforeQueryStatus += ReloadSettings; 41 | commandService.AddCommand(_menuItem); 42 | } 43 | 44 | /// 45 | /// Gets the instance of the command. 46 | /// 47 | public static NextImage Instance { get; private set; } 48 | 49 | public void ReloadSettings(object sender, EventArgs args) 50 | { 51 | if (ProvidersHolder.Instance.ActiveProvider is ISkipable skipable) 52 | activeSkipabe = skipable; 53 | else 54 | activeSkipabe = null; 55 | 56 | _menuItem.Enabled = activeSkipabe != null; 57 | } 58 | 59 | /// 60 | /// Initializes the singleton instance of the command. 61 | /// 62 | /// Owner package, not null. 63 | public static async Task InitializeAsync(AsyncPackage package) 64 | { 65 | // Switch to the main thread - the call to AddCommand in NextImage's constructor requires 66 | // the UI thread. 67 | if (Instance != null) return; 68 | await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken); 69 | var commandService = 70 | await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService; 71 | Instance = new NextImage(package, commandService); 72 | } 73 | 74 | /// 75 | /// This function is the callback used to execute the command when the menu item is clicked. 76 | /// See the constructor to see how the menu item is associated with this function using 77 | /// OleMenuCommandService service and MenuCommand class. 78 | /// 79 | /// Event sender. 80 | /// Event args. 81 | private void Execute(object sender, EventArgs e) 82 | { 83 | ThreadHelper.ThrowIfNotOnUIThread(); 84 | activeSkipabe.Skip(); 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /Shared/ImageProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Windows.Media.Imaging; 5 | using ClaudiaIDE.Settings; 6 | 7 | namespace ClaudiaIDE 8 | { 9 | public abstract class ImageProvider 10 | { 11 | protected readonly Setting Setting; 12 | protected BitmapSource Image; 13 | 14 | public ImageProvider(Setting setting, string solutionConfigFile, ImageBackgroundType providerType) 15 | { 16 | Setting = setting; 17 | Setting.OnChanged.AddEventHandler(OnSettingChanged); 18 | SolutionConfigFile = solutionConfigFile; 19 | ProviderType = providerType; 20 | } 21 | 22 | public ImageBackgroundType ProviderType { get; } 23 | 24 | public string SolutionConfigFile { get; } 25 | 26 | public bool IsActive { get; set; } 27 | 28 | public virtual BitmapSource GetBitmap() 29 | { 30 | return Image; 31 | } 32 | 33 | public abstract bool IsStaticImage(); 34 | public abstract string GetCurrentImageUri(); 35 | 36 | public event EventHandler NewImageAvailable; 37 | 38 | ~ImageProvider() 39 | { 40 | Setting.OnChanged.RemoveEventHandler(OnSettingChanged); 41 | } 42 | 43 | protected void FireImageAvailable() 44 | { 45 | NewImageAvailable?.Invoke(this, EventArgs.Empty); 46 | } 47 | 48 | protected abstract void OnSettingChanged(object sender, EventArgs e); 49 | } 50 | 51 | public class ProvidersHolder 52 | { 53 | private static readonly Lazy 54 | _instance = new Lazy(() => new ProvidersHolder()); 55 | 56 | private ProvidersHolder() 57 | { 58 | } 59 | 60 | public static ProvidersHolder Instance => _instance.Value; 61 | 62 | public List Providers { get; private set; } 63 | 64 | public ImageProvider ActiveProvider 65 | { 66 | get 67 | { 68 | var solfile = VisualStudioUtility.GetSolutionSettingsFileFullPath(); 69 | return Providers.FirstOrDefault(provider => string.IsNullOrEmpty(solfile) ? provider.IsActive : provider.SolutionConfigFile == solfile); 70 | } 71 | } 72 | 73 | public static void Initialize(Setting settings, List providers) 74 | { 75 | if (_instance.Value.Providers == null) _instance.Value.Providers = providers; 76 | var tp = _instance.Value.Providers?.FirstOrDefault(x => x.ProviderType == settings?.ImageBackgroundType); 77 | if (tp != null) tp.IsActive = true; 78 | } 79 | 80 | public ImageProvider ChangeActive(ImageBackgroundType newType, string solution) 81 | { 82 | Providers.ForEach(x => x.IsActive = false); 83 | var ret = Providers.FirstOrDefault(x => x.SolutionConfigFile == solution && x.ProviderType == newType); 84 | if (!string.IsNullOrEmpty(solution)) 85 | { 86 | ret = Providers.FirstOrDefault(x => x.SolutionConfigFile == solution); 87 | if (ret == null) 88 | { 89 | ret = Providers.FirstOrDefault(x => 90 | x.SolutionConfigFile == null && x.ProviderType == newType); 91 | } 92 | } 93 | else 94 | { 95 | ret = Providers.FirstOrDefault(x => 96 | x.SolutionConfigFile == null && x.ProviderType == newType); 97 | } 98 | ret.IsActive = true; 99 | return ret; 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /Shared/Helpers/ImageDownloader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using System.Windows.Media.Imaging; 6 | using ClaudiaIDE.Settings; 7 | 8 | namespace ClaudiaIDE.Helpers 9 | { 10 | internal class ImageDownloader 11 | { 12 | private static readonly HttpClient _client = new HttpClient(); 13 | private static BitmapImage _image; 14 | private static bool loading; 15 | 16 | public static async Task LoadImageAsync(string url, ImageStretch imageStretch, int maxWidth, int maxHeight, Setting setting) 17 | { 18 | if (string.IsNullOrEmpty(url)) return null; 19 | if (loading) return null; 20 | 21 | try 22 | { 23 | var cts = new CancellationTokenSource(); 24 | cts.CancelAfter(setting.WebApiDownloadInterval); 25 | var request = new HttpRequestMessage(HttpMethod.Get, new Uri(url)); 26 | request.Headers.Add("ContentType", "application/json; charset=utf-8"); 27 | var httpres = await _client.SendAsync(request, cts.Token); 28 | if (!httpres.IsSuccessStatusCode) return null; 29 | 30 | using (var memoryStream = await httpres.Content.ReadAsStreamAsync()) 31 | { 32 | _image = new BitmapImage(); 33 | _image.BeginInit(); 34 | _image.StreamSource = memoryStream; 35 | _image.StreamSource.Position = 0; 36 | _image.EndInit(); 37 | _image.Freeze(); 38 | 39 | if (imageStretch == ImageStretch.None) 40 | { 41 | if (maxHeight > 0 || maxWidth > 0) 42 | { 43 | var tmp = new BitmapImage(); 44 | tmp.BeginInit(); 45 | tmp.StreamSource = memoryStream; 46 | memoryStream.Position = 0; 47 | var modified = false; 48 | if (maxHeight > 0 && _image.PixelHeight > maxHeight) 49 | { 50 | if (_image.PixelHeight > _image.PixelWidth || maxWidth == 0) 51 | tmp.DecodePixelHeight = maxHeight; 52 | else 53 | tmp.DecodePixelWidth = maxWidth; 54 | modified = true; 55 | } 56 | 57 | if (maxWidth > 0 && _image.PixelWidth > maxHeight && !modified) 58 | { 59 | if (_image.PixelWidth > _image.PixelHeight || maxHeight == 0) 60 | tmp.DecodePixelWidth = maxWidth; 61 | else 62 | tmp.DecodePixelHeight = maxHeight; 63 | } 64 | 65 | tmp.EndInit(); 66 | tmp.Freeze(); 67 | _image = tmp; 68 | } 69 | } 70 | 71 | BitmapSource ret_bitmap = null; 72 | if ((_image.Width != _image.PixelWidth || _image.Height != _image.PixelHeight)) 73 | ret_bitmap = Utils.ConvertToDpi96(_image); 74 | 75 | if (setting.SoftEdgeX > 0 || setting.SoftEdgeY > 0) 76 | ret_bitmap = Utils.SoftenEdges(ret_bitmap ?? _image, setting.SoftEdgeX, setting.SoftEdgeY); 77 | 78 | loading = false; 79 | return ret_bitmap ?? _image; 80 | } 81 | } 82 | catch 83 | { 84 | return null; 85 | } 86 | } 87 | 88 | internal static void ResetUrl() 89 | { 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /Shared/ImageProviders/SingleImageProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Windows.Media.Imaging; 6 | using ClaudiaIDE.Helpers; 7 | using ClaudiaIDE.Settings; 8 | 9 | namespace ClaudiaIDE.ImageProviders 10 | { 11 | public class SingleImageProvider : ImageProvider 12 | { 13 | private BitmapImage _bitmap; 14 | private BitmapSource _bitmapSource; 15 | 16 | public SingleImageProvider(Setting setting, string solutionfile = null) : base(setting, solutionfile, 17 | ImageBackgroundType.Single) 18 | { 19 | LoadImage(); 20 | } 21 | 22 | protected override void OnSettingChanged(object sender, EventArgs e) 23 | { 24 | if ((sender as Setting)?.ImageBackgroundType != ImageBackgroundType.Single) return; 25 | LoadImage(); 26 | FireImageAvailable(); 27 | } 28 | 29 | 30 | public override BitmapSource GetBitmap() 31 | { 32 | if (_bitmap == null && _bitmapSource != null) return _bitmapSource; 33 | if (_bitmap != null && _bitmapSource == null) return _bitmap; 34 | return _bitmap; 35 | } 36 | 37 | public override bool IsStaticImage() 38 | { 39 | if (string.IsNullOrEmpty(Setting.BackgroundImageAbsolutePath)) return true; 40 | var fileInfo = new FileInfo(Setting.BackgroundImageAbsolutePath); 41 | return !Setting.SupportVideoFileExtensions.Any(x => x == fileInfo.Extension.ToLower()); 42 | } 43 | 44 | private void LoadImage() 45 | { 46 | try 47 | { 48 | var fileUri = new Uri(Setting.BackgroundImageAbsolutePath, UriKind.RelativeOrAbsolute); 49 | var fileInfo = new FileInfo(Setting.BackgroundImageAbsolutePath); 50 | if (Setting.SupportVideoFileExtensions.Any(x => x == fileInfo.Extension.ToLower())) return; 51 | if (fileInfo.Exists) 52 | { 53 | _bitmapSource = null; 54 | try 55 | { 56 | _bitmap = new BitmapImage(); 57 | _bitmap.BeginInit(); 58 | _bitmap.CacheOption = BitmapCacheOption.OnLoad; 59 | _bitmap.CreateOptions = BitmapCreateOptions.None; 60 | _bitmap.UriSource = fileUri; 61 | _bitmap.EndInit(); 62 | _bitmap.Freeze(); 63 | } 64 | catch 65 | { 66 | // maybe not supported exception 67 | _bitmap = new BitmapImage(); 68 | _bitmap.Freeze(); 69 | } 70 | 71 | if (Setting.ImageStretch == ImageStretch.None) 72 | _bitmap = Utils.EnsureMaxWidthHeight(_bitmap, Setting.MaxWidth, Setting.MaxHeight); 73 | 74 | BitmapSource ret_bitmap = null; 75 | if (Setting.ImageStretch == ImageStretch.None && 76 | (_bitmap.Width != _bitmap.PixelWidth || _bitmap.Height != _bitmap.PixelHeight) 77 | ) 78 | ret_bitmap = Utils.ConvertToDpi96(_bitmap); 79 | else 80 | ret_bitmap = _bitmap; 81 | 82 | if (Setting.SoftEdgeX > 0 || Setting.SoftEdgeY > 0) 83 | ret_bitmap = Utils.SoftenEdges(ret_bitmap ?? _bitmap, Setting.SoftEdgeX, Setting.SoftEdgeY); 84 | 85 | if (ret_bitmap != null) 86 | { 87 | _bitmapSource = ret_bitmap; 88 | _bitmap = null; 89 | } 90 | } 91 | else 92 | { 93 | _bitmap = null; 94 | _bitmapSource = null; 95 | } 96 | } 97 | catch { } 98 | } 99 | 100 | public override string GetCurrentImageUri() 101 | { 102 | return Setting.BackgroundImageAbsolutePath; 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /Shared/ImageProviders/WebApiImageProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Net.Http; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using System.Timers; 8 | using ClaudiaIDE.Helpers; 9 | using ClaudiaIDE.Interfaces; 10 | using ClaudiaIDE.Settings; 11 | using Microsoft.VisualStudio.Threading; 12 | using Newtonsoft.Json.Linq; 13 | 14 | namespace ClaudiaIDE.ImageProviders 15 | { 16 | internal class WebApiImageProvider : ImageProvider, IPausable, ISkipable 17 | { 18 | private static HttpClient _client = new HttpClient(); 19 | private PausableTimer _timer; 20 | private string _currentUrl; 21 | 22 | public WebApiImageProvider(Setting setting, string solutionConfigFile = null) : base(setting, 23 | solutionConfigFile, ImageBackgroundType.WebApi) 24 | { 25 | OnSettingChanged(setting, null); 26 | } 27 | 28 | public bool IsPaused => _timer.IsPaused; 29 | 30 | public void Pause() 31 | { 32 | if (!IsPaused) _timer.Pause(); 33 | } 34 | 35 | public void Resume() 36 | { 37 | if (IsPaused) _timer.Resume(); 38 | } 39 | 40 | public void Skip() 41 | { 42 | _timer.Stop(); 43 | ChangeImage(); 44 | if (IsPaused) 45 | _timer.Pause(); 46 | } 47 | 48 | private void ChangeImage() 49 | { 50 | ChangeImageAsync().Forget(); 51 | } 52 | 53 | private async Task ChangeImageAsync() 54 | { 55 | if (Setting.ImageBackgroundType != ImageBackgroundType.WebApi) return; 56 | if (_timer.IsPaused) return; 57 | 58 | try 59 | { 60 | var cts = new CancellationTokenSource(); 61 | cts.CancelAfter(Setting.WebApiDownloadInterval); 62 | var request = new HttpRequestMessage(HttpMethod.Get, new Uri(Setting.WebApiEndpoint)); 63 | request.Headers.Add("ContentType", "application/json; charset=utf-8"); 64 | var httpres = await _client.SendAsync(request, cts.Token); 65 | if (!httpres.IsSuccessStatusCode) return; 66 | var response = await httpres.Content.ReadAsStringAsync(); 67 | 68 | var jsonObject = JObject.Parse(response); 69 | var imageUrl = jsonObject.SelectToken(Setting.WebApiJsonKey); 70 | if (imageUrl != null) 71 | { 72 | _currentUrl = imageUrl.ToString(); 73 | if (!IsStaticImage()) 74 | { 75 | FireImageAvailable(); 76 | return; 77 | } 78 | Image = await ImageDownloader.LoadImageAsync(_currentUrl, Setting.ImageStretch, Setting.MaxWidth, Setting.MaxHeight, Setting); 79 | _timer.Restart(); 80 | if (Image != null) FireImageAvailable(); 81 | return; 82 | } 83 | } 84 | catch { } 85 | } 86 | 87 | protected override void OnSettingChanged(object sender, EventArgs e) 88 | { 89 | if (_timer != null) 90 | { 91 | _timer.Stop(); 92 | _timer.Elapsed -= OnTimerElapsed; 93 | _timer.Dispose(); 94 | } 95 | 96 | _timer = new PausableTimer(Setting.WebApiDownloadInterval.TotalMilliseconds); 97 | _timer.Elapsed += OnTimerElapsed; 98 | 99 | if ((sender as Setting)?.ImageBackgroundType != ImageBackgroundType.WebApi) 100 | { 101 | _timer.Stop(); 102 | return; 103 | } 104 | 105 | ImageDownloader.ResetUrl(); 106 | ChangeImage(); 107 | } 108 | 109 | private void OnTimerElapsed(object sender, ElapsedEventArgs e) 110 | { 111 | ChangeImage(); 112 | } 113 | 114 | public override bool IsStaticImage() 115 | { 116 | if (string.IsNullOrEmpty(_currentUrl)) return true; 117 | var f = new FileInfo(new Uri(_currentUrl).LocalPath); 118 | return !Setting.SupportVideoFileExtensions.Any(x => x == f.Extension.ToLower()); 119 | } 120 | 121 | public override string GetCurrentImageUri() 122 | { 123 | return _currentUrl; 124 | } 125 | } 126 | } -------------------------------------------------------------------------------- /Shared/Helpers/ImageSourceAnimator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | using System.Windows.Controls; 4 | using System.Windows.Media; 5 | using System.Windows.Media.Animation; 6 | 7 | namespace ClaudiaIDE.Helpers 8 | { 9 | internal static class ImageSourceAnimator 10 | { 11 | public static void AnimateImageSourceChange(this Brush background, ImageBrush newImage, 12 | Action onChangeImage, AnimateImageChangeParams animateImageChangeParams = null) 13 | { 14 | var animationParameters = animateImageChangeParams ?? new AnimateImageChangeParams(); 15 | 16 | if (background != null) 17 | { 18 | var fadeOutAnimation = new DoubleAnimation(0d, animationParameters.FadeTime) { AutoReverse = false }; 19 | var fadeInAnimation = 20 | new DoubleAnimation(0d, animationParameters.TargetOpacity, animationParameters.FadeTime) 21 | { AutoReverse = false }; 22 | 23 | fadeOutAnimation.Completed += (o, e) => 24 | { 25 | newImage.Opacity = 0d; 26 | onChangeImage(newImage); 27 | background.Opacity = animationParameters.TargetOpacity; 28 | newImage.BeginAnimation(Brush.OpacityProperty, fadeInAnimation); 29 | }; 30 | 31 | background.BeginAnimation(Brush.OpacityProperty, fadeOutAnimation); 32 | } 33 | else 34 | { 35 | newImage.Opacity = animateImageChangeParams.TargetOpacity; 36 | onChangeImage(newImage); 37 | } 38 | } 39 | 40 | public static void AnimateImageSourceChange(this Brush background, VisualBrush newVisual, 41 | Action onChangeVisual, AnimateImageChangeParams animateImageChangeParams = null) 42 | { 43 | var animationParameters = animateImageChangeParams ?? new AnimateImageChangeParams(); 44 | 45 | if (background != null) 46 | { 47 | var fadeOutAnimation = new DoubleAnimation(0d, animationParameters.FadeTime) { AutoReverse = false }; 48 | var fadeInAnimation = 49 | new DoubleAnimation(0d, animationParameters.TargetOpacity, animationParameters.FadeTime) 50 | { AutoReverse = false }; 51 | 52 | fadeOutAnimation.Completed += (o, e) => 53 | { 54 | newVisual.Opacity = 0d; 55 | onChangeVisual(newVisual); 56 | background.Opacity = animationParameters.TargetOpacity; 57 | newVisual.BeginAnimation(Brush.OpacityProperty, fadeInAnimation); 58 | }; 59 | 60 | background.BeginAnimation(Brush.OpacityProperty, fadeOutAnimation); 61 | } 62 | else 63 | { 64 | newVisual.Opacity = animateImageChangeParams.TargetOpacity; 65 | onChangeVisual(newVisual); 66 | } 67 | } 68 | 69 | public static void AnimateImageSourceChange(this Image image, 70 | ImageSource newImage, 71 | Action onChangeImage, 72 | AnimateImageChangeParams animateImageChangeParams = null) 73 | { 74 | var animationParameters = animateImageChangeParams ?? new AnimateImageChangeParams(); 75 | 76 | if (image != null) 77 | { 78 | var fadeOutAnimation = new DoubleAnimation(0d, animationParameters.FadeTime) { AutoReverse = false }; 79 | var fadeInAnimation = 80 | new DoubleAnimation(0d, animationParameters.TargetOpacity, animationParameters.FadeTime) 81 | { AutoReverse = false }; 82 | 83 | fadeOutAnimation.Completed += (o, e) => 84 | { 85 | onChangeImage(image); 86 | image.Source = newImage; 87 | RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.Fant); 88 | image.BeginAnimation(UIElement.OpacityProperty, fadeInAnimation); 89 | }; 90 | image.BeginAnimation(UIElement.OpacityProperty, fadeOutAnimation); 91 | } 92 | else 93 | { 94 | image.Opacity = animateImageChangeParams.TargetOpacity; 95 | image.Source = newImage; 96 | onChangeImage(image); 97 | } 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /Shared/Settings/WeakEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using System.Reflection; 5 | 6 | namespace ClaudiaIDE.Settings 7 | { 8 | // https://gist.github.com/wonderful-panda/3b68a9a6040d89df907b 9 | 10 | public class WeakHandler : IEquatable> 11 | where TEventArgs : EventArgs 12 | { 13 | private readonly Action _action; 14 | private readonly MethodInfo _method; 15 | private readonly WeakReference _targetRef; 16 | 17 | public WeakHandler(EventHandler handler) 18 | { 19 | if (handler == null) 20 | throw new ArgumentNullException("handler"); 21 | _targetRef = handler.Target != null ? new WeakReference(handler.Target) : null; 22 | _method = handler.Method; 23 | _action = CreateOpenMethod(handler); 24 | } 25 | 26 | /// 27 | /// 元になったイベントハンドラがstaticメソッドかどうか 28 | /// 29 | public bool IsStatic => _targetRef == null; 30 | 31 | /// 32 | /// イベントリスナがまだ生きているかどうか 33 | /// 34 | public bool IsAlive => IsStatic || _targetRef.IsAlive; 35 | 36 | public bool Equals(EventHandler other) 37 | { 38 | if (other.Target == null) 39 | return _targetRef == null && _method == other.Method; 40 | return _targetRef != null && _targetRef.Target == other.Target && _method == other.Method; 41 | } 42 | 43 | /// 44 | /// 指定されたdelegateのTargetとMethodを元に、以下のようなActionを生成して返す 45 | /// instanceメソッドの場合 46 | /// (object target, object sender, TArg e) => ((TargetType)target).Method(sender, e) 47 | /// staticメソッドの場合 48 | /// (object target, object sender, TArg e) => TargetType.Method(sender, e) 49 | /// 50 | private Action CreateOpenMethod(EventHandler h) 51 | { 52 | var target = Expression.Parameter(typeof(object), "target"); 53 | var sender = Expression.Parameter(typeof(object), "sender"); 54 | var e = Expression.Parameter(typeof(TEventArgs), "e"); 55 | 56 | // null or (TargetType)target 57 | var instance = h.Target == null ? null : Expression.Convert(target, h.Target.GetType()); 58 | 59 | var expression = 60 | // (target, sender, e) => *** 61 | Expression.Lambda>( 62 | // ***.Method(sender, e) 63 | Expression.Call(instance, h.Method, sender, e) 64 | , target, sender, e); 65 | 66 | return expression.Compile(); 67 | } 68 | 69 | /// 70 | /// イベントハンドラを呼び出す 71 | /// 72 | public void Invoke(object sender, TEventArgs e) 73 | { 74 | if (IsStatic) 75 | { 76 | _action(null, sender, e); 77 | } 78 | else 79 | { 80 | var target = _targetRef.Target; 81 | if (target != null) 82 | _action(target, sender, e); 83 | } 84 | } 85 | } 86 | 87 | public class WeakEvent where TEventArgs : EventArgs 88 | { 89 | private readonly List> _handlers = new List>(); 90 | 91 | public void AddEventHandler(EventHandler handler) 92 | { 93 | lock (_handlers) 94 | { 95 | _handlers.RemoveAll(w => !w.IsAlive); 96 | _handlers.Add(new WeakHandler(handler)); 97 | } 98 | } 99 | 100 | public void RemoveEventHandler(EventHandler handler) 101 | { 102 | lock (_handlers) 103 | { 104 | _handlers.RemoveAll(w => !w.IsAlive || w.Equals(handler)); 105 | } 106 | } 107 | 108 | public void RaiseEvent(object sender, TEventArgs e) 109 | { 110 | WeakHandler[] handlers; 111 | lock (_handlers) 112 | { 113 | _handlers.RemoveAll(w => !w.IsAlive); 114 | handlers = _handlers.ToArray(); 115 | } 116 | 117 | foreach (var h in handlers) 118 | h.Invoke(sender, e); 119 | } 120 | } 121 | } -------------------------------------------------------------------------------- /Shared/VSPackage.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // このコードはツールによって生成されました。 4 | // ランタイム バージョン:4.0.30319.42000 5 | // 6 | // このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 7 | // コードが再生成されるときに損失したりします。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ClaudiaIDE { 12 | using System; 13 | 14 | 15 | /// 16 | /// ローカライズされた文字列などを検索するための、厳密に型指定されたリソース クラスです。 17 | /// 18 | // このクラスは StronglyTypedResourceBuilder クラスが ResGen 19 | // または Visual Studio のようなツールを使用して自動生成されました。 20 | // メンバーを追加または削除するには、.ResX ファイルを編集して、/str オプションと共に 21 | // ResGen を実行し直すか、または VS プロジェクトをビルドし直します。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class VSPackage { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal VSPackage() { 33 | } 34 | 35 | /// 36 | /// このクラスで使用されているキャッシュされた ResourceManager インスタンスを返します。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ClaudiaIDE.VSPackage", typeof(VSPackage).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// すべてについて、現在のスレッドの CurrentUICulture プロパティをオーバーライドします 51 | /// 現在のスレッドの CurrentUICulture プロパティをオーバーライドします。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// ClaudiaIDE に類似しているローカライズされた文字列を検索します。 65 | /// 66 | internal static string _110 { 67 | get { 68 | return ResourceManager.GetString("110", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// This extension change the background image of editor. に類似しているローカライズされた文字列を検索します。 74 | /// 75 | internal static string _112 { 76 | get { 77 | return ResourceManager.GetString("112", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Light theme に類似しているローカライズされた文字列を検索します。 83 | /// 84 | internal static string _116 { 85 | get { 86 | return ResourceManager.GetString("116", resourceCulture); 87 | } 88 | } 89 | 90 | /// 91 | /// Dark theme に類似しているローカライズされた文字列を検索します。 92 | /// 93 | internal static string _117 { 94 | get { 95 | return ResourceManager.GetString("117", resourceCulture); 96 | } 97 | } 98 | 99 | /// 100 | /// General に類似しているローカライズされた文字列を検索します。 101 | /// 102 | internal static string _118 { 103 | get { 104 | return ResourceManager.GetString("118", resourceCulture); 105 | } 106 | } 107 | 108 | /// 109 | /// (アイコン) に類似した型 System.Drawing.Icon のローカライズされたリソースを検索します。 110 | /// 111 | internal static System.Drawing.Icon _400 { 112 | get { 113 | object obj = ResourceManager.GetObject("400", resourceCulture); 114 | return ((System.Drawing.Icon)(obj)); 115 | } 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /Shared/MenuCommands/PauseSlideshow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Design; 3 | using Task = System.Threading.Tasks.Task; 4 | using ClaudiaIDE.Interfaces; 5 | using Microsoft.VisualStudio.Shell; 6 | 7 | namespace ClaudiaIDE.MenuCommands 8 | { 9 | /// 10 | /// Command handler 11 | /// 12 | internal sealed class PauseSlideshow 13 | { 14 | /// 15 | /// Command ID. 16 | /// 17 | public const int PauseCommandId = 0x0110; 18 | 19 | public const int ResumeCommandId = 0x0120; 20 | 21 | /// 22 | /// Command menu group (command set GUID). 23 | /// 24 | public static readonly Guid CommandSet = new Guid(GuidList.MenuSetId); 25 | 26 | private IPausable pausable; 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// Adds our command handlers for menu (commands must exist in the command table file) 31 | /// 32 | /// Owner package, not null. 33 | /// Command service to add command to, not null. 34 | private PauseSlideshow(AsyncPackage package, OleMenuCommandService commandService) 35 | { 36 | commandService = commandService ?? throw new ArgumentNullException(nameof(commandService)); 37 | 38 | var pauseCommandID = new CommandID(CommandSet, PauseCommandId); 39 | var resumeCommandID = new CommandID(CommandSet, ResumeCommandId); 40 | var pauseMenuItem = new OleMenuCommand(Execute, pauseCommandID); 41 | var resumeMenuItem = new OleMenuCommand(Execute, resumeCommandID); 42 | UpdatePauseVisibility(pauseMenuItem); 43 | UpdateResumeVisibility(resumeMenuItem); 44 | pauseMenuItem.BeforeQueryStatus += (sender, args) => 45 | { 46 | if (!(sender is OleMenuCommand cmd)) return; 47 | UpdatePauseVisibility(cmd); 48 | }; 49 | resumeMenuItem.BeforeQueryStatus += (sender, args) => 50 | { 51 | if (!(sender is OleMenuCommand cmd)) return; 52 | UpdateResumeVisibility(cmd); 53 | }; 54 | commandService.AddCommand(pauseMenuItem); 55 | commandService.AddCommand(resumeMenuItem); 56 | } 57 | 58 | /// 59 | /// Gets the instance of the command. 60 | /// 61 | public static PauseSlideshow Instance { get; private set; } 62 | 63 | private void UpdatePauseVisibility(OleMenuCommand cmd) 64 | { 65 | var activePaused = GetActivePausable(); 66 | cmd.Visible = activePaused == null || !activePaused.IsPaused; 67 | cmd.Enabled = activePaused != null && !activePaused.IsPaused; 68 | } 69 | 70 | private void UpdateResumeVisibility(OleMenuCommand cmd) 71 | { 72 | var activePaused = GetActivePausable(); 73 | cmd.Visible = activePaused != null && activePaused.IsPaused; 74 | cmd.Enabled = activePaused != null; 75 | } 76 | 77 | 78 | private IPausable GetActivePausable() 79 | { 80 | if (pausable != null) 81 | if (pausable is ImageProvider imageProvider && imageProvider.IsActive) 82 | return pausable; 83 | 84 | var activeProvider = ProvidersHolder.Instance.ActiveProvider; 85 | if (activeProvider is IPausable provider) 86 | { 87 | pausable = provider; 88 | return provider; 89 | } 90 | 91 | return null; 92 | } 93 | 94 | /// 95 | /// Initializes the singleton instance of the command. 96 | /// 97 | /// Owner package, not null. 98 | public static async Task InitializeAsync(AsyncPackage package) 99 | { 100 | // Switch to the main thread - the call to AddCommand in PauseSlideshow's constructor requires 101 | // the UI thread. 102 | if (Instance != null) return; 103 | await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken); 104 | 105 | var commandService = 106 | await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService; 107 | Instance = new PauseSlideshow(package, commandService); 108 | } 109 | 110 | /// 111 | /// This function is the callback used to execute the command when the menu item is clicked. 112 | /// See the constructor to see how the menu item is associated with this function using 113 | /// OleMenuCommandService service and MenuCommand class. 114 | /// 115 | /// Event sender. 116 | /// Event args. 117 | private void Execute(object sender, EventArgs e) 118 | { 119 | ThreadHelper.ThrowIfNotOnUIThread(); 120 | var pausable = GetActivePausable(); 121 | if (pausable != null) 122 | { 123 | if (pausable.IsPaused) 124 | pausable.Resume(); 125 | else 126 | pausable.Pause(); 127 | } 128 | } 129 | } 130 | } -------------------------------------------------------------------------------- /Shared/ClaudiaIDEFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.Composition; 4 | using System.Linq; 5 | using ClaudiaIDE.ImageProviders; 6 | using ClaudiaIDE.Settings; 7 | using EnvDTE; 8 | using Microsoft.VisualStudio.Shell; 9 | using Microsoft.VisualStudio.Text.Editor; 10 | using Microsoft.VisualStudio.Utilities; 11 | 12 | namespace ClaudiaIDE 13 | { 14 | #region Adornment Factory 15 | 16 | /// 17 | /// Establishes an to place the adornment on and exports the 18 | /// 19 | /// that instantiates the adornment on the event of a 's creation 20 | /// 21 | [Export(typeof(IWpfTextViewCreationListener))] 22 | [ContentType("text")] 23 | [ContentType("BuildOutput")] 24 | [TextViewRole(PredefinedTextViewRoles.Document)] 25 | internal sealed class ClaudiaIDEAdornmentFactory : IWpfTextViewCreationListener 26 | { 27 | private List ImageProviders; 28 | 29 | [Import(typeof(SVsServiceProvider))] internal IServiceProvider ServiceProvider { get; set; } 30 | 31 | /// 32 | /// Defines the adornment layer for the scarlet adornment. This layer is ordered 33 | /// after the selection layer in the Z-order 34 | /// 35 | [Export(typeof(AdornmentLayerDefinition))] 36 | [Name("ClaudiaIDE")] 37 | [Order(Before = PredefinedAdornmentLayers.DifferenceChanges)] 38 | public AdornmentLayerDefinition EditorAdornmentLayer { get; set; } 39 | 40 | /// 41 | /// Instantiates a ClaudiaIDE manager when a textView is created. 42 | /// 43 | /// The upon which the adornment should be placed 44 | public void TextViewCreated(IWpfTextView textView) 45 | { 46 | ThreadHelper.ThrowIfNotOnUIThread(); 47 | var settings = Setting.Initialize((DTE)ServiceProvider.GetService(typeof(DTE))); 48 | var solution = VisualStudioUtility.GetSolutionSettingsFileFullPath(); 49 | 50 | if (ImageProviders == null) 51 | { 52 | if (ProvidersHolder.Instance.Providers == null) 53 | { 54 | if (string.IsNullOrEmpty(solution)) 55 | { 56 | ProvidersHolder.Initialize(settings, new List 57 | { 58 | new SingleImageEachProvider(settings), 59 | new SlideShowImageProvider(settings), 60 | new SingleImageProvider(settings), 61 | new SingleImageWebProvider(settings), 62 | new WebApiImageProvider(settings) 63 | }); 64 | } 65 | else 66 | { 67 | ProvidersHolder.Initialize(settings, new List()); 68 | switch (settings.ImageBackgroundType) 69 | { 70 | case ImageBackgroundType.Single: 71 | ProvidersHolder.Instance.Providers.Add(new SingleImageProvider(settings, solution)); 72 | break; 73 | case ImageBackgroundType.SingleEach: 74 | ProvidersHolder.Instance.Providers.Add(new SingleImageEachProvider(settings, solution)); 75 | break; 76 | case ImageBackgroundType.Slideshow: 77 | ProvidersHolder.Instance.Providers.Add(new SlideShowImageProvider(settings, solution)); 78 | break; 79 | case ImageBackgroundType.WebSingle: 80 | ProvidersHolder.Instance.Providers.Add(new SingleImageWebProvider(settings, solution)); 81 | break; 82 | case ImageBackgroundType.WebApi: 83 | ProvidersHolder.Instance.Providers.Add(new WebApiImageProvider(settings, solution)); 84 | break; 85 | default: 86 | ProvidersHolder.Instance.Providers.Add(new SingleImageEachProvider(settings, solution)); 87 | break; 88 | } 89 | } 90 | } 91 | 92 | ImageProviders = ProvidersHolder.Instance.Providers; 93 | } 94 | 95 | if (!string.IsNullOrEmpty(solution)) 96 | if (!ImageProviders.Any(x => x.SolutionConfigFile == solution)) 97 | switch (settings.ImageBackgroundType) 98 | { 99 | case ImageBackgroundType.Single: 100 | ImageProviders.Add(new SingleImageProvider(settings, solution)); 101 | break; 102 | case ImageBackgroundType.SingleEach: 103 | ImageProviders.Add(new SingleImageEachProvider(settings, solution)); 104 | break; 105 | case ImageBackgroundType.Slideshow: 106 | ImageProviders.Add(new SlideShowImageProvider(settings, solution)); 107 | break; 108 | case ImageBackgroundType.WebSingle: 109 | ImageProviders.Add(new SingleImageWebProvider(settings, solution)); 110 | break; 111 | case ImageBackgroundType.WebApi: 112 | ProvidersHolder.Instance.Providers.Add(new WebApiImageProvider(settings, solution)); 113 | break; 114 | default: 115 | ImageProviders.Add(new SingleImageEachProvider(settings, solution)); 116 | break; 117 | } 118 | 119 | new ClaudiaIDE(textView, ImageProviders); 120 | } 121 | } 122 | 123 | #endregion //Adornment Factory 124 | } -------------------------------------------------------------------------------- /Shared/ImageProviders/SingleImageEachProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Windows.Media.Imaging; 6 | using ClaudiaIDE.Helpers; 7 | using ClaudiaIDE.Settings; 8 | 9 | namespace ClaudiaIDE.ImageProviders 10 | { 11 | public class SingleImageEachProvider : ImageProvider 12 | { 13 | private ImageFiles _imageFiles; 14 | private IEnumerator _imageFilesPath; 15 | private FileSystemWatcher _fileWatcher; 16 | 17 | public SingleImageEachProvider(Setting setting, string solutionfile = null) : base(setting, solutionfile, 18 | ImageBackgroundType.SingleEach) 19 | { 20 | OnSettingChanged(setting, null); 21 | } 22 | 23 | private ImageFiles GetImagesFromDirectory() 24 | { 25 | return new ImageFiles 26 | { 27 | Extensions = Setting.Extensions, 28 | ImageDirectoryPath = Setting.BackgroundImagesDirectoryAbsolutePath, 29 | Shuffle = Setting.ShuffleSlideshow 30 | }; 31 | } 32 | 33 | public override BitmapSource GetBitmap() 34 | { 35 | try 36 | { 37 | if (_imageFiles == null) 38 | { 39 | ReEnumerationFiles(); 40 | _imageFilesPath.MoveNext(); 41 | } 42 | var current = _imageFilesPath?.Current; 43 | if (string.IsNullOrEmpty(current) || !IsStaticImage()) return null; 44 | 45 | var bitmap = new BitmapImage(); 46 | BitmapSource ret_bitmap = null; 47 | var fileInfo = new FileInfo(current); 48 | if (fileInfo.Exists) 49 | { 50 | try 51 | { 52 | bitmap.BeginInit(); 53 | bitmap.CacheOption = BitmapCacheOption.OnLoad; 54 | bitmap.CreateOptions = BitmapCreateOptions.None; 55 | bitmap.UriSource = new Uri(current, UriKind.RelativeOrAbsolute); 56 | bitmap.EndInit(); 57 | bitmap.Freeze(); 58 | } 59 | catch 60 | { 61 | // maybe not supported exception 62 | bitmap = new BitmapImage(); 63 | bitmap.Freeze(); 64 | } 65 | if (Setting.ImageStretch == ImageStretch.None) 66 | bitmap = Utils.EnsureMaxWidthHeight(bitmap, Setting.MaxWidth, Setting.MaxHeight); 67 | 68 | if (Setting.ImageStretch == ImageStretch.None && 69 | (bitmap.Width != bitmap.PixelWidth || bitmap.Height != bitmap.PixelHeight) 70 | ) 71 | ret_bitmap = Utils.ConvertToDpi96(bitmap); 72 | else 73 | ret_bitmap = bitmap; 74 | 75 | if (Setting.SoftEdgeX > 0 || Setting.SoftEdgeY > 0) 76 | ret_bitmap = Utils.SoftenEdges(ret_bitmap ?? bitmap, Setting.SoftEdgeX, Setting.SoftEdgeY); 77 | } 78 | else 79 | { 80 | ReEnumerationFiles(); 81 | _imageFilesPath.MoveNext(); 82 | return GetBitmap(); 83 | } 84 | 85 | if (ret_bitmap != null) return ret_bitmap; 86 | else return bitmap; 87 | } 88 | catch (ArgumentOutOfRangeException) 89 | { 90 | if (_imageFilesPath?.MoveNext() ?? false) 91 | { 92 | return GetBitmap(); 93 | } 94 | else 95 | { 96 | _imageFilesPath?.Reset(); 97 | return null; 98 | } 99 | } 100 | catch 101 | { 102 | return null; 103 | } 104 | } 105 | 106 | private void ReEnumerationFiles() 107 | { 108 | _imageFiles = GetImagesFromDirectory(); 109 | _imageFilesPath = _imageFiles.GetEnumerator(); 110 | } 111 | 112 | protected override void OnSettingChanged(object sender, EventArgs e) 113 | { 114 | if ((sender as Setting)?.ImageBackgroundType != ImageBackgroundType.SingleEach) 115 | { 116 | _fileWatcher?.Dispose(); 117 | return; 118 | } 119 | ReEnumerationFiles(); 120 | NextImage(); 121 | 122 | _fileWatcher?.Dispose(); 123 | if (File.Exists((sender as Setting)?.BackgroundImagesDirectoryAbsolutePath)) 124 | { 125 | _fileWatcher = new FileSystemWatcher((sender as Setting)?.BackgroundImagesDirectoryAbsolutePath) 126 | { 127 | IncludeSubdirectories = false, 128 | InternalBufferSize = 32 * 1024, 129 | NotifyFilter = NotifyFilters.FileName | NotifyFilters.CreationTime | NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size 130 | }; 131 | _fileWatcher.Changed += new FileSystemEventHandler(OnDirectoryChanged); 132 | _fileWatcher.EnableRaisingEvents = true; 133 | } 134 | } 135 | 136 | private void OnDirectoryChanged(object source, FileSystemEventArgs e) 137 | { 138 | ReEnumerationFiles(); 139 | } 140 | 141 | public void NextImage() 142 | { 143 | if (_imageFiles == null) 144 | { 145 | ReEnumerationFiles(); 146 | } 147 | if (!_imageFilesPath.MoveNext()) 148 | if (Setting.LoopSlideshow) 149 | { 150 | _imageFilesPath.Reset(); 151 | _imageFilesPath.MoveNext(); 152 | } 153 | } 154 | 155 | public override bool IsStaticImage() 156 | { 157 | if (string.IsNullOrEmpty(_imageFilesPath?.Current)) return true; 158 | var fileInfo = new FileInfo(_imageFilesPath?.Current); 159 | return !Setting.SupportVideoFileExtensions.Any(x => x == fileInfo.Extension.ToLower()); 160 | } 161 | 162 | public override string GetCurrentImageUri() 163 | { 164 | return _imageFilesPath?.Current; 165 | } 166 | } 167 | } -------------------------------------------------------------------------------- /Shared/Helpers/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Drawing.Imaging; 4 | using System.Windows; 5 | using System.Windows.Media; 6 | using System.Windows.Media.Imaging; 7 | using MessageBox = System.Windows.Forms.MessageBox; 8 | 9 | namespace ClaudiaIDE.Helpers 10 | { 11 | internal static class Utils 12 | { 13 | private static byte[] pixelByteArray; 14 | 15 | public static BitmapImage EnsureMaxWidthHeight(BitmapImage original, int maxWidth, int maxHeight) 16 | { 17 | BitmapImage bitmap = null; 18 | 19 | if (maxWidth > 0 && maxHeight > 0 20 | && original.PixelWidth > maxWidth && original.PixelHeight > maxHeight) 21 | { 22 | try 23 | { 24 | bitmap = new BitmapImage(); 25 | bitmap.BeginInit(); 26 | bitmap.CacheOption = BitmapCacheOption.OnLoad; 27 | bitmap.CreateOptions = BitmapCreateOptions.None; 28 | bitmap.UriSource = original.UriSource; 29 | bitmap.DecodePixelWidth = maxWidth; 30 | bitmap.DecodePixelHeight = maxHeight; 31 | bitmap.EndInit(); 32 | bitmap.Freeze(); 33 | } 34 | catch 35 | { 36 | // maybe not supported exception 37 | bitmap = new BitmapImage(); 38 | bitmap.Freeze(); 39 | } 40 | return bitmap; 41 | } 42 | 43 | if (maxWidth > 0 && original.PixelWidth > maxWidth) 44 | { 45 | try 46 | { 47 | bitmap = new BitmapImage(); 48 | bitmap.BeginInit(); 49 | bitmap.CacheOption = BitmapCacheOption.OnLoad; 50 | bitmap.CreateOptions = BitmapCreateOptions.None; 51 | bitmap.UriSource = original.UriSource; 52 | bitmap.DecodePixelWidth = maxWidth; 53 | bitmap.EndInit(); 54 | bitmap.Freeze(); 55 | } 56 | catch 57 | { 58 | // maybe not supported exception 59 | bitmap = new BitmapImage(); 60 | bitmap.Freeze(); 61 | } 62 | return bitmap; 63 | } 64 | 65 | if (maxHeight > 0 && original.PixelHeight > maxHeight) 66 | { 67 | try 68 | { 69 | bitmap = new BitmapImage(); 70 | bitmap.BeginInit(); 71 | bitmap.CacheOption = BitmapCacheOption.OnLoad; 72 | bitmap.CreateOptions = BitmapCreateOptions.None; 73 | bitmap.UriSource = original.UriSource; 74 | bitmap.DecodePixelHeight = maxHeight; 75 | bitmap.EndInit(); 76 | bitmap.Freeze(); 77 | } 78 | catch 79 | { 80 | // maybe not supported exception 81 | bitmap = new BitmapImage(); 82 | bitmap.Freeze(); 83 | } 84 | return bitmap; 85 | } 86 | 87 | return original; 88 | } 89 | 90 | public static BitmapSource ConvertToDpi96(BitmapSource source) 91 | { 92 | var dpi = 96; 93 | var width = source.PixelWidth; 94 | var height = source.PixelHeight; 95 | 96 | var stride = width * 4; 97 | var pixelData = new byte[stride * height]; 98 | source.CopyPixels(pixelData, stride, 0); 99 | 100 | var ret = BitmapSource.Create(width, height, dpi, dpi, PixelFormats.Bgra32, null, pixelData, stride); 101 | ret.Freeze(); 102 | return ret; 103 | } 104 | 105 | public static BitmapSource SoftenEdges(BitmapSource original, int softedgex, int softedgey) 106 | { 107 | if (softedgex <= 0 && softedgey <= 0) return original; 108 | 109 | try 110 | { 111 | //32bit assumption 112 | if (original.Format.BitsPerPixel != 32) return original; 113 | 114 | //limit softedge range by half image size 115 | softedgex = Math.Min(softedgex, (int)(original.Width / 2)); 116 | softedgey = Math.Min(softedgey, (int)(original.Height / 2)); 117 | 118 | var height = original.PixelHeight; 119 | var width = original.PixelWidth; 120 | var bytesPerPixel = (original.Format.BitsPerPixel + 7) / 8; 121 | var nStride = width * bytesPerPixel; 122 | 123 | pixelByteArray = new byte[height * nStride]; 124 | original.CopyPixels(pixelByteArray, nStride, 0); 125 | 126 | //alpha and color 127 | for (var y = 0; y < height; y++) 128 | { 129 | var fAlphaByY = 1f; 130 | var nDistToEdgeY = Math.Min(y, height - 1 - y); 131 | fAlphaByY = (float)nDistToEdgeY / softedgey; 132 | fAlphaByY = Math.Min(fAlphaByY, 1.0f); 133 | 134 | for (var x = 0; x < width; x++) 135 | { 136 | var fAlphaByX = 1f; 137 | var nDistToEdgeX = Math.Min(x, width - 1 - x); 138 | fAlphaByX = (float)nDistToEdgeX / softedgex; 139 | fAlphaByX = Math.Min(fAlphaByX, 1.0f); 140 | 141 | for (var iPix = 0; iPix < 4; iPix++) 142 | { 143 | var alpha_offset_in_array = bytesPerPixel * (x + y * width) + iPix; 144 | int alphaOld = pixelByteArray[alpha_offset_in_array]; 145 | var alphaNew = (int)Math.Floor(alphaOld * fAlphaByX * fAlphaByY); 146 | pixelByteArray[alpha_offset_in_array] = (byte)alphaNew; 147 | } 148 | } 149 | } 150 | 151 | var bs = BitmapSource.Create(width, 152 | height, 153 | original.DpiX, 154 | original.DpiY, 155 | PixelFormats.Pbgra32, 156 | original.Palette, 157 | pixelByteArray, 158 | nStride); 159 | bs.Freeze(); 160 | return bs; 161 | } 162 | catch 163 | { 164 | } 165 | 166 | return original; 167 | } 168 | } 169 | } -------------------------------------------------------------------------------- /Shared/VSPackage.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | ClaudiaIDE 122 | 123 | 124 | This extension change the background image of editor. 125 | 126 | 127 | 128 | Resources\400.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 129 | 130 | 131 | Light theme 132 | 133 | 134 | Dark theme 135 | 136 | 137 | General 138 | 139 | -------------------------------------------------------------------------------- /ClaudiaIDE16/ClaudiaIDE16.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16.0 5 | 16.0 6 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 7 | 8 | 9 | 10 | Debug 11 | AnyCPU 12 | 2.0 13 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | {E803B36C-090C-4155-B13C-EAE30CA78AA7} 15 | Library 16 | Properties 17 | ClaudiaIDE 18 | ClaudiaIDE.16 19 | v4.7.2 20 | true 21 | true 22 | false 23 | true 24 | true 25 | true 26 | Program 27 | $(DevEnvDir)devenv.exe 28 | /rootsuffix Exp 29 | 30 | 31 | true 32 | full 33 | false 34 | bin\Debug\ 35 | DEBUG;TRACE 36 | prompt 37 | 4 38 | True 39 | False 40 | 41 | 42 | pdbonly 43 | true 44 | bin\Release\ 45 | TRACE 46 | prompt 47 | 4 48 | False 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | Localized\ResLocalized.Designer.cs 74 | 75 | 76 | VSPackage.Designer.cs 77 | True 78 | True 79 | VSPackage.resx 80 | 81 | 82 | 83 | 84 | 85 | 86 | Designer 87 | 88 | 89 | 90 | 91 | 2.4.0 92 | 93 | 94 | 17.14.28 95 | 96 | 97 | compile; build; native; contentfiles; analyzers; buildtransitive 98 | 99 | 100 | runtime; build; native; contentfiles; analyzers; buildtransitive 101 | all 102 | 103 | 104 | 13.0.4 105 | 106 | 107 | 4.3.4 108 | 109 | 110 | 1.1.1 111 | 112 | 113 | 114 | 115 | Menus.ctmenu 116 | ClaudiaIdePackage.vsct 117 | 118 | 119 | Menus.ctmenu 120 | ClaudiaIdePackage.vsct 121 | 122 | 123 | ClaudiaIdePackageVsct.cs 124 | 125 | 126 | Menus.ctmenu 127 | ClaudiaIdePackage.vsct 128 | 129 | 130 | 131 | 132 | config.txt 133 | Always 134 | true 135 | 136 | 137 | Images\background.png 138 | Always 139 | true 140 | 141 | 142 | Images\background2.png 143 | Always 144 | true 145 | 146 | 147 | Resources\400.ico 148 | Always 149 | 150 | 151 | Resources\ClaudiaIDEMenu.png 152 | true 153 | Always 154 | 155 | 156 | Resources\ss.png 157 | true 158 | Always 159 | 160 | 161 | Resources\vsixicon.png 162 | true 163 | Always 164 | 165 | 166 | 167 | 168 | Localized\ResLocalized.en-US.resx 169 | true 170 | ResLocalized.en-US.Designer.cs 171 | Designer 172 | 173 | 174 | Localized\ResLocalized.ja-JP.resx 175 | true 176 | ResLocalized.ja-JP.Designer.cs 177 | Designer 178 | 179 | 180 | Localized\ResLocalized.resx 181 | true 182 | ResLocalized.Designer.cs 183 | Designer 184 | 185 | 186 | Localized\ResLocalized.zh-CN.resx 187 | true 188 | ResLocalized.zh-CN.Designer.cs 189 | Designer 190 | 191 | 192 | 193 | 194 | true 195 | 196 | 197 | 198 | 205 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ClaudiaIDE 2 | ========== 3 | 4 | This is a Visual Studio extension that lets you set a custom background image or slideshow. 5 | 6 | ## What's new 7 | 8 | - Ver 3.1.16 Experimental support about animation gif and mp4 video file play in background. 9 | - Ver 3.1.7 Support OS color theme setting and dark theme setting. 10 | - Ver 3.1.6 Add `Toggle Background Image Visibility` menu. 11 | - Ver 3.0.3 Support tiled image in editor window. 12 | - Ver 3.0.1 The ClaudiaIDE has been split into two Visual Studio versions, because the older version that needs to be resolved dependency of EnvDTE in Visual Studio 2022. 13 | - Ver 3.0.0 support Visual Studio 2022 preview 1. However unfortunately drop off support for Visual Studio 2017. If you want support VS2017 ver, you can try use [ver 2.2.19](https://github.com/buchizo/ClaudiaIDE/releases/tag/Release2.2.19). Now mainstream is support Visual Studio 2019 and 2022 only. 14 | - Ver 2.2.16 or later can support configuration per solution. 15 | 16 | ![Save setings for solution](Images/config-per-solution.png) 17 | 18 | After save, this extension create .claudiaideconfig file in solution directory from current settings in option dialog. If you want to modify settings, you can modify this file (JSON format) or override via that menu. 19 | 20 | #### Limitation 21 | 22 | - Current feature of solution settings require restart Visual Studio after changed configfile. 23 | 24 | ## Versions 25 | 26 | - This extension support some multiple versions Visual Studio, but it is not single VSIX/assembly file. 27 | 28 | Visual Studio | support ClaudiaIDE 29 | --|-- 30 | Visual Studio 2012 ~ 2015 | [1.28.6](https://github.com/buchizo/ClaudiaIDE/releases/tag/Release1.28.6) 31 | Visual Studio 2017 | [2.2.19](https://github.com/buchizo/ClaudiaIDE/releases/tag/Release2.2.19) 32 | Visual Studio 2019 | [2.2.19](https://github.com/buchizo/ClaudiaIDE/releases/tag/Release2.2.19) or [3.0.0.11](https://github.com/buchizo/ClaudiaIDE/releases/tag/Release3.0.0.11) or [3.0.1](https://github.com/buchizo/ClaudiaIDE/releases/tag/Release3.0.1)+ 33 | Visual Studio 2022 | [3.0.1](https://github.com/buchizo/ClaudiaIDE/releases/tag/Release3.0.1)+ 34 | 35 | - After ver 3.0.1, I will single code maintenance that target to multiple Visual Studio versions. This mean build to some VSIX files as follows ClaudiaIDE.vsix (for VS2022) and ClaudiaIDE.16.vsix (for VS2019). If new Visual Studio major version (e.g. 18.x) release, I'll add ClaudiaIDE17 (for VS2022). And ClaudiaIDE support version slide to new Visual Studio. (ClaudiaIDE's csproj support to always on latest Visual Studio) 36 | 37 | ## About options 38 | 39 | ### Tiled support 40 | 41 | Ver 3.0.3+ support tiled image like as [WPF Tiling behavior](https://docs.microsoft.com/en-us/dotnet/desktop/wpf/graphics-multimedia/tilebrush-overview?view=netframeworkdesktop-4.8#tiling-behavior). 42 | 43 | * nomal (default) 44 | 45 | ![normal settings](Images/tile02.png) 46 | ![normal](Images/tile01.png) 47 | 48 | * tiled 49 | 50 | ![tiled settings](Images/tile03.png) 51 | ![tiled](Images/tile04.png) 52 | 53 | ### How to expand to IDE 54 | 55 | 1. Open option menu in Visual Studio (Tools -> Options) 56 | 2. Expand to IDE property set to True in ClaudiaIDE option page. 57 | 58 | ![expand to IDE option](Images/howto01.png) 59 | 60 | 3. You can use [Transparency Theme](https://marketplace.visualstudio.com/items?itemName=pengweiqhca.transparency) extension. Or customise Visual Studio theme using color theme editor (E.g. [Visual Studio 2015 Color Theme Editor](https://visualstudiogallery.msdn.microsoft.com/6f4b51b6-5c6b-4a81-9cb5-f2daa560430b)) 61 | 4. Click "Create Copy of Theme" button, And "Edit Theme" 62 | 63 | ![copy theme](Images/howto02.png) ![Edit theme](Images/howto03.png) 64 | 65 | 5. Customise some colors opacity as follows (your own risk) : 66 | 67 | ![Edit opacity](Images/howto04.png) 68 | 69 | * Solution Explorer 70 | * TreeView -> Background 71 | * IDE and text editor 72 | * Environment -> Window 73 | * Environment -> EnvironmentBackground 74 | * Environment -> EnvironmentBackgroundGradientBegin 75 | * Environment -> EnvironmentBackgroundGradientEnd 76 | * Environment -> EnvironmentBackgroundGradientMiddle1 77 | * Environment -> EnvironmentBackgroundGradientMiddle2 78 | * Window Title 79 | * Environment -> MainWindowActiveCaption 80 | * Environment -> MainWindowInactiveCaption 81 | * Command Bar 82 | * Environment -> CommandShelfBackgroundGradientBegin 83 | * Environment -> CommandShelfBackgroundGradientEnd 84 | * Environment -> CommandShelfBackgroundGradientMiddle 85 | * Environment -> CommandShelfHighlightGradientBegin 86 | * Environment -> CommandShelfHighlightGradientEnd 87 | * Environment -> CommandShelfHighlightGradientMiddle 88 | * Environment -> CommandBarGradientBegin 89 | * Environment -> CommandBarGradientEnd 90 | * Environment -> CommandBarGradientMiddle 91 | * Environment -> CommandBarToolBarBorder 92 | 93 | * Example: 94 | 95 | ![sample](Images/example01.png) 96 | 97 | ## Version histories (summary) 98 | 99 | ### ver 2.2.x 100 | 101 | Flickering has maybe been decreased, however the image fade interval option isn't supported for slideshows because problem effect by this update. If you want to expand the image to the full IDE window ("expand to IDE" option), ClaudiaIDE does not require theme editor. ClaudiaIDE automaticaly makes some backgrounds transparent (e.g. the text editor). However, for now, some windows, such as the solution explorer, still need to be made transaperent with theme editor, like as [Color Theme Editor for Visual Studio 2019](https://marketplace.visualstudio.com/items?itemName=VisualStudioPlatformTeam.VisualStudio2019ColorThemeEditor). 102 | 103 | Enabling the option "User hardware graphics acceleration if available" will reduce flickering. 104 | 105 | ![hardware acceleration](Images/workaround01.png) 106 | 107 | ### ver 2.1.0 108 | 109 | Support versions changed as follows: 110 | 111 | * Visual Studio 2017 (15.8 or later) 112 | * Visual Studio 2019 (preview or RTM) 113 | 114 | #### Braking Changes 115 | 116 | Visual Studio 2019 (16.1) extensions can support AsyncPackage only. ClaudiaIDE's this version change to AsyncPackage. 117 | 118 | AsyncPackage can support Visual Studio 2015 or later. I decided move to forward and I don't support old Visual Studio versions (2017 15.8 or earlier). If you want to use this extension on old Visual Studio versions (2017 15.8 or earlier), you can use [1.28.6](https://github.com/buchizo/ClaudiaIDE/releases/tag/Release1.28.6). 119 | 120 | * If you already install 2.0.x to Visual Studio 2015 or Visual Studio 2017 (15.8 or ealier), you will uninstall 2.0.x and re-install 1.28.6 ClaudiaIDE.vsix. 121 | 122 | ### ver 1.28.6 123 | 124 | Support Visual Studio 2019 Preview 1 125 | 126 | ### ver 1.26 127 | 128 | Support Visual Studio 2017 (RTM) 129 | 130 | ### ver 1.24 131 | 132 | * Add feature (beta) : background image expand to IDE. 133 | * Known issue: If background image expand to IDE, editor background does not show when editor was moved to floating window with slideshow until next image. 134 | 135 | ### ver 1.23 136 | 137 | * Add image stretch feature and improve performance 138 | 139 | ### ver 1.19 140 | 141 | * Additional support Visual Studio "15" Preview 142 | * Can specifie max image size. 143 | 144 | ### ver 1.18 145 | 146 | * Add slideshow feature. 147 | * Support Visual Studio 2012/2013/2015 148 | 149 | Download: 150 | 151 | [ClaudiaIDE (Visual Studio Gallery)](http://visualstudiogallery.msdn.microsoft.com/9ba50f8d-f30c-4e33-ab19-bfd9f56eb817 "ClaudiaIDE (Visual Studio Gallery)") 152 | 153 | # License 154 | 155 | ## Microsoft Public License (Ms-PL) 156 | 157 | This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. 158 | 159 | Definitions 160 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. 161 | 162 | A "contribution" is the original software, or any additions or changes to the software. 163 | 164 | A "contributor" is any person that distributes its contribution under this license. 165 | 166 | "Licensed patents" are a contributor's patent claims that read directly on its contribution. 167 | 168 | Grant of Rights 169 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. 170 | 171 | (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. 172 | 173 | Conditions and Limitations 174 | (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. 175 | 176 | (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. 177 | 178 | (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. 179 | 180 | (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. 181 | 182 | (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. 183 | -------------------------------------------------------------------------------- /ClaudiaIDE/ClaudiaIDE.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16.0 5 | 16.0 6 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 7 | 8 | 9 | 10 | 11 | 14.0 12 | publish\ 13 | true 14 | Disk 15 | false 16 | Foreground 17 | 7 18 | Days 19 | false 20 | false 21 | true 22 | 0 23 | 1.0.0.%2a 24 | false 25 | false 26 | true 27 | 28 | 29 | 30 | 31 | 32 | false 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Debug 41 | AnyCPU 42 | 10.0.20305 43 | 2.0 44 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 45 | {FA0103C8-8CCD-4A1E-AF09-9862C9A4A04A} 46 | Library 47 | Properties 48 | ClaudiaIDE 49 | ClaudiaIDE 50 | v4.7.2 51 | 512 52 | 53 | 54 | true 55 | full 56 | false 57 | bin\Debug\ 58 | DEBUG;TRACE 59 | prompt 60 | 4 61 | True 62 | True 63 | False 64 | 65 | 66 | pdbonly 67 | true 68 | bin\Release\ 69 | TRACE 70 | prompt 71 | 4 72 | False 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | Localized\ResLocalized.Designer.cs 98 | True 99 | True 100 | ResLocalized.resx 101 | 102 | 103 | VSPackage.Designer.cs 104 | True 105 | True 106 | VSPackage.resx 107 | 108 | 109 | 110 | 111 | 112 | 113 | Designer 114 | 115 | 116 | 117 | 118 | 3.1.4 119 | 120 | 121 | 2.4.0 122 | 123 | 124 | 17.0.31902.203 125 | 126 | 127 | 17.14.2120 128 | runtime; build; native; contentfiles; analyzers; buildtransitive 129 | all 130 | 131 | 132 | 13.0.4 133 | 134 | 135 | 1.1.1 136 | 137 | 138 | 139 | 140 | Menus.ctmenu 141 | ClaudiaIdePackage.vsct 142 | 143 | 144 | Menus.ctmenu 145 | ClaudiaIdePackage.vsct 146 | 147 | 148 | ClaudiaIdePackageVsct.cs 149 | 150 | 151 | Menus.ctmenu 152 | ClaudiaIdePackage.vsct 153 | 154 | 155 | 156 | 157 | config.txt 158 | Always 159 | true 160 | 161 | 162 | Images\background.png 163 | Always 164 | true 165 | 166 | 167 | Images\background2.png 168 | Always 169 | true 170 | 171 | 172 | Resources\400.ico 173 | Always 174 | 175 | 176 | Resources\ClaudiaIDEMenu.png 177 | true 178 | Always 179 | 180 | 181 | Resources\ss.png 182 | true 183 | Always 184 | 185 | 186 | Resources\vsixicon.png 187 | true 188 | Always 189 | 190 | 191 | 192 | 193 | Localized\ResLocalized.en-US.resx 194 | true 195 | ResLocalized.en-US.Designer.cs 196 | Designer 197 | 198 | 199 | Localized\ResLocalized.ja-JP.resx 200 | true 201 | ResLocalized.ja-JP.Designer.cs 202 | Designer 203 | 204 | 205 | Localized\ResLocalized.resx 206 | true 207 | ResLocalized.Designer.cs 208 | Designer 209 | PublicResXFileCodeGenerator 210 | 211 | 212 | Localized\ResLocalized.zh-CN.resx 213 | true 214 | ResLocalized.zh-CN.Designer.cs 215 | Designer 216 | 217 | 218 | 219 | 220 | true 221 | 222 | 223 | 224 | 231 | -------------------------------------------------------------------------------- /Shared/ImageProviders/SlideShowImageProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Timers; 7 | using System.Windows.Media.Imaging; 8 | using ClaudiaIDE.Helpers; 9 | using ClaudiaIDE.Interfaces; 10 | using ClaudiaIDE.Settings; 11 | 12 | namespace ClaudiaIDE.ImageProviders 13 | { 14 | public class SlideShowImageProvider : ImageProvider, IPausable, ISkipable 15 | { 16 | private PausableTimer _timer; 17 | private ImageFiles _imageFiles; 18 | private IEnumerator _imageFilesPath; 19 | private FileSystemWatcher _fileWatcher; 20 | 21 | public SlideShowImageProvider(Setting setting, string solutionfile = null) : base(setting, solutionfile, 22 | ImageBackgroundType.Slideshow) 23 | { 24 | OnSettingChanged(setting, null); 25 | } 26 | 27 | public bool IsPaused => _timer.IsPaused; 28 | 29 | public void Pause() 30 | { 31 | if (!IsPaused) _timer.Pause(); 32 | } 33 | 34 | public void Resume() 35 | { 36 | if (IsPaused) _timer.Resume(); 37 | } 38 | 39 | public void Skip() 40 | { 41 | ChangeImage(); 42 | } 43 | 44 | private void OnTimerElapsed(object sender, ElapsedEventArgs e) 45 | { 46 | NextImage(); 47 | } 48 | 49 | private ImageFiles GetImagesFromDirectory() 50 | { 51 | return new ImageFiles 52 | { 53 | Extensions = Setting.Extensions, 54 | ImageDirectoryPath = Setting.BackgroundImagesDirectoryAbsolutePath, 55 | Shuffle = Setting.ShuffleSlideshow, 56 | IncludeSubdirectories = Setting.IncludeSubdirectories, 57 | }; 58 | } 59 | 60 | public override BitmapSource GetBitmap() 61 | { 62 | try 63 | { 64 | if (_imageFiles == null) 65 | { 66 | ReEnumerationFiles(); 67 | _imageFilesPath.MoveNext(); 68 | _timer.Restart(); 69 | } 70 | var current = _imageFilesPath?.Current; 71 | if (string.IsNullOrEmpty(current) || !IsStaticImage()) return null; 72 | 73 | var bitmap = new BitmapImage(); 74 | var fileInfo = new FileInfo(current); 75 | if (fileInfo.Exists) 76 | { 77 | try 78 | { 79 | bitmap.BeginInit(); 80 | bitmap.CacheOption = BitmapCacheOption.OnLoad; 81 | bitmap.CreateOptions = BitmapCreateOptions.None; 82 | bitmap.UriSource = new Uri(current, UriKind.RelativeOrAbsolute); 83 | bitmap.EndInit(); 84 | bitmap.Freeze(); 85 | } 86 | catch 87 | { 88 | // maybe not supported exception 89 | bitmap = new BitmapImage(); 90 | bitmap.Freeze(); 91 | } 92 | } 93 | else 94 | { 95 | ReEnumerationFiles(); 96 | _imageFilesPath.MoveNext(); 97 | return GetBitmap(); 98 | } 99 | 100 | BitmapSource ret_bitmap = bitmap; 101 | if (Setting.ImageStretch == ImageStretch.None) 102 | { 103 | bitmap = Utils.EnsureMaxWidthHeight(bitmap, Setting.MaxWidth, Setting.MaxHeight); 104 | 105 | if (bitmap.Width != bitmap.PixelWidth || bitmap.Height != bitmap.PixelHeight) 106 | ret_bitmap = Utils.ConvertToDpi96(bitmap); 107 | else 108 | ret_bitmap = bitmap; 109 | } 110 | 111 | if (Setting.SoftEdgeX > 0 || Setting.SoftEdgeY > 0) 112 | ret_bitmap = Utils.SoftenEdges(ret_bitmap, Setting.SoftEdgeX, Setting.SoftEdgeY); 113 | 114 | return ret_bitmap; 115 | } 116 | catch (ArgumentOutOfRangeException) 117 | { 118 | if (_imageFilesPath?.MoveNext() ?? false) 119 | { 120 | return GetBitmap(); 121 | } 122 | else 123 | { 124 | _imageFilesPath?.Reset(); 125 | return null; 126 | } 127 | } 128 | catch 129 | { 130 | return null; 131 | } 132 | } 133 | 134 | private void ReEnumerationFiles() 135 | { 136 | _imageFiles = GetImagesFromDirectory(); 137 | _imageFilesPath = _imageFiles.GetEnumerator(); 138 | } 139 | 140 | protected override void OnSettingChanged(object sender, EventArgs e) 141 | { 142 | if (_timer != null) 143 | { 144 | _timer.Stop(); 145 | _timer.Elapsed -= OnTimerElapsed; 146 | _timer.Dispose(); 147 | } 148 | _timer = new PausableTimer(Setting.UpdateImageInterval.TotalMilliseconds); 149 | _timer.Elapsed += OnTimerElapsed; 150 | 151 | if ((sender as Setting)?.ImageBackgroundType != ImageBackgroundType.Slideshow) 152 | { 153 | _timer.Stop(); 154 | } 155 | else 156 | { 157 | ReEnumerationFiles(); 158 | ChangeImage(); 159 | _timer.Restart(); 160 | } 161 | 162 | _fileWatcher?.Dispose(); 163 | if (Directory.Exists((sender as Setting)?.BackgroundImagesDirectoryAbsolutePath)) 164 | { 165 | _fileWatcher = new FileSystemWatcher((sender as Setting)?.BackgroundImagesDirectoryAbsolutePath) 166 | { 167 | IncludeSubdirectories = Setting.IncludeSubdirectories, 168 | InternalBufferSize = 32 * 1024, 169 | NotifyFilter = NotifyFilters.FileName | NotifyFilters.CreationTime | NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size 170 | }; 171 | _fileWatcher.Changed += new FileSystemEventHandler(OnDirectoryChanged); 172 | _fileWatcher.EnableRaisingEvents = true; 173 | } 174 | } 175 | 176 | private void OnDirectoryChanged(object source, FileSystemEventArgs e) 177 | { 178 | ReEnumerationFiles(); 179 | } 180 | 181 | public void NextImage() 182 | { 183 | if (Setting.ImageBackgroundType != ImageBackgroundType.Slideshow) return; 184 | ChangeImage(); 185 | } 186 | 187 | protected void ChangeImage() 188 | { 189 | if (_imageFiles == null) 190 | { 191 | ReEnumerationFiles(); 192 | } 193 | if (_imageFilesPath.MoveNext()) 194 | { 195 | FireImageAvailable(); 196 | _timer.Restart(); 197 | } 198 | else 199 | { 200 | // Reached the end of the images. Loop to beginning? 201 | if (Setting.LoopSlideshow) 202 | { 203 | _imageFilesPath.Reset(); 204 | if (_imageFilesPath.MoveNext()) 205 | { 206 | FireImageAvailable(); 207 | _timer.Restart(); 208 | } 209 | else 210 | { 211 | _timer.Stop(); 212 | } 213 | } 214 | else 215 | { 216 | _timer.Stop(); 217 | } 218 | } 219 | } 220 | 221 | public override bool IsStaticImage() 222 | { 223 | if (string.IsNullOrEmpty(_imageFilesPath?.Current)) return true; 224 | var fileInfo = new FileInfo(_imageFilesPath?.Current); 225 | return !Setting.SupportVideoFileExtensions.Any(x => x == fileInfo.Extension.ToLower()); 226 | } 227 | 228 | public override string GetCurrentImageUri() 229 | { 230 | return _imageFilesPath?.Current; 231 | } 232 | } 233 | 234 | public class ImageFiles : IEnumerable 235 | { 236 | public string Extensions { get; set; } 237 | public string ImageDirectoryPath { get; set; } 238 | public bool Shuffle { get; set; } 239 | public bool IncludeSubdirectories { get; set; } 240 | 241 | private static DateTime LastEnumerationTime = DateTime.MinValue; 242 | private static List LastImages; 243 | 244 | public IEnumerator GetEnumerator() 245 | { 246 | // to avoid multiple, repeated enumerations of the images due to settings changes or other events, check 247 | // whether this method has been called in the last 2 seconds 248 | if (LastImages != null && DateTime.Now - LastEnumerationTime < TimeSpan.FromSeconds(2)) { 249 | return new ImageFilesEnumerator(LastImages); 250 | } 251 | LastEnumerationTime = DateTime.Now; 252 | 253 | List imageFilePaths; 254 | 255 | if (!string.IsNullOrEmpty(Extensions) && !string.IsNullOrEmpty(ImageDirectoryPath) && Directory.Exists(ImageDirectoryPath)) 256 | { 257 | var extensions = Extensions 258 | .Split(new[] { ",", " " }, StringSplitOptions.RemoveEmptyEntries) 259 | .Select(x => x.ToUpper()); 260 | 261 | var searchOption = IncludeSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; 262 | 263 | imageFilePaths = Directory 264 | .EnumerateFiles(new DirectoryInfo(ImageDirectoryPath).FullName, "*.*", searchOption) 265 | .Where(x => extensions.Contains(Path.GetExtension(x).ToUpper())).OrderBy(x => x).ToList(); 266 | 267 | if (imageFilePaths.Any()) 268 | { 269 | if (Shuffle) imageFilePaths.Shuffle(); 270 | } 271 | } 272 | else 273 | { 274 | imageFilePaths = new List(); 275 | } 276 | 277 | LastImages = imageFilePaths; 278 | return new ImageFilesEnumerator(LastImages); 279 | } 280 | 281 | IEnumerator IEnumerable.GetEnumerator() 282 | { 283 | return GetEnumerator(); 284 | } 285 | } 286 | 287 | public class ImageFilesEnumerator : IEnumerator 288 | { 289 | private readonly List imageFilePaths; 290 | private int position; 291 | 292 | public ImageFilesEnumerator(List imageFilePaths) 293 | { 294 | this.imageFilePaths = imageFilePaths; 295 | position = -1; 296 | } 297 | 298 | public string Current => position < 0 || position > imageFilePaths.Count ? null : imageFilePaths[position]; 299 | 300 | object IEnumerator.Current => Current; 301 | 302 | public void Dispose() 303 | { 304 | } 305 | 306 | public bool MoveNext() 307 | { 308 | position++; 309 | return position < imageFilePaths.Count; 310 | } 311 | 312 | public void Reset() 313 | { 314 | position = -1; 315 | } 316 | } 317 | } -------------------------------------------------------------------------------- /ClaudiaIDE/Resources/ClaudiaIdePackage.zh-CN.vsct: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 11 | 12 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 35 | 36 | 40 | 41 | 44 | 46 | 47 | 50 | 52 | 53 | 54 | 55 | 56 | 60 | 62 | 63 | ClaudiaIDE 64 | ClaudiaIDE 65 | .ClaudiaIDE.ClaudiaIDEMenu 66 | 67 | 68 | 69 | 70 | 72 | 73 | 80 | 93 | 107 | 123 | 134 | 145 | 156 | 167 | 178 | 179 | 180 | 181 | 182 | 187 | 190 | 191 | 192 | 193 | 194 | 200 | 205 | 206 | 207 | 208 | 209 | 211 | 212 | 213 | 215 | 217 | 219 | 221 | 223 | 225 | 227 | 229 | 231 | 233 | 235 | 237 | 238 | 239 | 241 | 243 | 245 | 247 | 248 | 249 | -------------------------------------------------------------------------------- /ClaudiaIDE16/Resources/ClaudiaIdePackage.zh-CN.vsct: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 11 | 12 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 35 | 36 | 40 | 41 | 44 | 46 | 47 | 50 | 52 | 53 | 54 | 55 | 56 | 60 | 62 | 63 | ClaudiaIDE 64 | ClaudiaIDE 65 | .ClaudiaIDE.ClaudiaIDEMenu 66 | 67 | 68 | 69 | 70 | 72 | 73 | 80 | 93 | 107 | 123 | 134 | 145 | 156 | 167 | 178 | 179 | 180 | 181 | 182 | 187 | 190 | 191 | 192 | 193 | 194 | 200 | 205 | 206 | 207 | 208 | 209 | 211 | 212 | 213 | 215 | 217 | 219 | 221 | 223 | 225 | 227 | 229 | 231 | 233 | 235 | 237 | 238 | 239 | 241 | 243 | 245 | 247 | 248 | 249 | -------------------------------------------------------------------------------- /ClaudiaIDE/Resources/ClaudiaIdePackage.ja-JP.vsct: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 11 | 12 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 35 | 36 | 40 | 41 | 44 | 46 | 47 | 50 | 52 | 53 | 54 | 55 | 56 | 60 | 62 | 63 | ClaudiaIDE 64 | ClaudiaIDE 65 | .ClaudiaIDE.ClaudiaIDEMenu 66 | 67 | 68 | 69 | 70 | 72 | 73 | 80 | 93 | 107 | 123 | 134 | 145 | 156 | 167 | 178 | 179 | 180 | 181 | 182 | 187 | 190 | 191 | 192 | 193 | 194 | 200 | 205 | 206 | 207 | 208 | 209 | 211 | 212 | 213 | 215 | 217 | 219 | 221 | 223 | 225 | 227 | 229 | 231 | 233 | 235 | 237 | 238 | 239 | 241 | 243 | 245 | 247 | 248 | 249 | -------------------------------------------------------------------------------- /ClaudiaIDE16/Resources/ClaudiaIdePackage.ja-JP.vsct: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 11 | 12 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 35 | 36 | 40 | 41 | 44 | 46 | 47 | 50 | 52 | 53 | 54 | 55 | 56 | 60 | 62 | 63 | ClaudiaIDE 64 | ClaudiaIDE 65 | .ClaudiaIDE.ClaudiaIDEMenu 66 | 67 | 68 | 69 | 70 | 72 | 73 | 80 | 93 | 107 | 123 | 134 | 145 | 156 | 167 | 178 | 179 | 180 | 181 | 182 | 187 | 190 | 191 | 192 | 193 | 194 | 200 | 205 | 206 | 207 | 208 | 209 | 211 | 212 | 213 | 215 | 217 | 219 | 221 | 223 | 225 | 227 | 229 | 231 | 233 | 235 | 237 | 238 | 239 | 241 | 243 | 245 | 247 | 248 | 249 | --------------------------------------------------------------------------------