diff --git a/QuickLook.Common/Commands/AsyncRelayCommand.cs b/QuickLook.Common/Commands/AsyncRelayCommand.cs new file mode 100644 index 0000000..0abcbf1 --- /dev/null +++ b/QuickLook.Common/Commands/AsyncRelayCommand.cs @@ -0,0 +1,59 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace QuickLook.Common.Commands; + +public class AsyncRelayCommand(Func execute, Func canExecute = null) : ICommand +{ + private readonly Func _execute = execute ?? throw new ArgumentNullException(nameof(execute)); + private readonly Func _canExecute = canExecute ?? (() => true); + private bool _isExecuting; + + public bool CanExecute(object parameter) + { + return !_isExecuting && _canExecute(); + } + + public async void Execute(object parameter) + { + if (!CanExecute(parameter)) + return; + + _isExecuting = true; + RaiseCanExecuteChanged(); + try + { + await _execute(); + } + finally + { + _isExecuting = false; + RaiseCanExecuteChanged(); + } + } + + public event EventHandler CanExecuteChanged; + + public void RaiseCanExecuteChanged() + { + CanExecuteChanged?.Invoke(this, EventArgs.Empty); + } +} diff --git a/QuickLook.Common/Commands/RelayCommand.cs b/QuickLook.Common/Commands/RelayCommand.cs new file mode 100644 index 0000000..125455d --- /dev/null +++ b/QuickLook.Common/Commands/RelayCommand.cs @@ -0,0 +1,36 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Windows.Input; + +namespace QuickLook.Common.Commands; + +public class RelayCommand(Action execute, Func canExecute = null) : ICommand +{ + private readonly Action _execute = execute; + private readonly Func _canExecute = canExecute; + + public bool CanExecute(object parameter) => _canExecute?.Invoke() ?? true; + + public void Execute(object parameter) => _execute(); + + public event EventHandler CanExecuteChanged; + + public void RaiseCanExecuteChanged() => + CanExecuteChanged?.Invoke(this, EventArgs.Empty); +} diff --git a/QuickLook.Common/Controls/FontSymbols.cs b/QuickLook.Common/Controls/FontSymbols.cs new file mode 100644 index 0000000..85972a1 --- /dev/null +++ b/QuickLook.Common/Controls/FontSymbols.cs @@ -0,0 +1,1436 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +namespace QuickLook.Common.Controls; + +/// +/// Segoe Fluent Icons +/// https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font +/// +public sealed class FontSymbols +{ + public const string GlobalNavButton = "\xe700"; + public const string Wifi = "\xe701"; + public const string Bluetooth = "\xe702"; + public const string Connect = "\xe703"; + public const string InternetSharing = "\xe704"; + public const string VPN = "\xe705"; + public const string Brightness = "\xe706"; + public const string MapPin = "\xe707"; + public const string QuietHours = "\xe708"; + public const string Airplane = "\xe709"; + public const string Tablet = "\xe70a"; + public const string QuickNote = "\xe70b"; + public const string RememberedDevice = "\xe70c"; + public const string ChevronDown = "\xe70d"; + public const string ChevronUp = "\xe70e"; + public const string Edit = "\xe70f"; + public const string Add = "\xe710"; + public const string Cancel = "\xe711"; + public const string More = "\xe712"; + public const string Settings = "\xe713"; + public const string Video = "\xe714"; + public const string Mail = "\xe715"; + public const string People = "\xe716"; + public const string Phone = "\xe717"; + public const string Pin = "\xe718"; + public const string Shop = "\xe719"; + public const string Stop = "\xe71a"; + public const string Link = "\xe71b"; + public const string Filter = "\xe71c"; + public const string AllApps = "\xe71d"; + public const string Zoom = "\xe71e"; + public const string ZoomOut = "\xe71f"; + public const string Microphone = "\xe720"; + public const string Search = "\xe721"; + public const string Camera = "\xe722"; + public const string Attach = "\xe723"; + public const string Send = "\xe724"; + public const string SendFill = "\xe725"; + public const string WalkSolid = "\xe726"; + public const string InPrivate = "\xe727"; + public const string FavoriteList = "\xe728"; + public const string PageSolid = "\xe729"; + public const string Forward = "\xe72a"; + public const string Back = "\xe72b"; + public const string Refresh = "\xe72c"; + public const string Share = "\xe72d"; + public const string Lock = "\xe72e"; + public const string BlockedSite = "\xe72f"; + public const string ReportHacked = "\xe730"; + public const string EMI = "\xe731"; + public const string Blocked = "\xe733"; + public const string FavoriteStar = "\xe734"; + public const string FavoriteStarFill = "\xe735"; + public const string ReadingMode = "\xe736"; + public const string Favicon = "\xe737"; + public const string Remove = "\xe738"; + public const string Checkbox = "\xe739"; + public const string CheckboxComposite = "\xe73a"; + public const string CheckboxFill = "\xe73b"; + public const string CheckboxIndeterminate = "\xe73c"; + public const string CheckboxCompositeReversed = "\xe73d"; + public const string CheckMark = "\xe73e"; + public const string BackToWindow = "\xe73f"; + public const string FullScreen = "\xe740"; + public const string ResizeTouchLarger = "\xe741"; + public const string ResizeTouchSmaller = "\xe742"; + public const string ResizeMouseSmall = "\xe743"; + public const string ResizeMouseMedium = "\xe744"; + public const string ResizeMouseWide = "\xe745"; + public const string ResizeMouseTall = "\xe746"; + public const string ResizeMouseLarge = "\xe747"; + public const string SwitchUser = "\xe748"; + public const string Print = "\xe749"; + public const string Up = "\xe74a"; + public const string Down = "\xe74b"; + public const string OEM = "\xe74c"; + public const string Delete = "\xe74d"; + public const string Save = "\xe74e"; + public const string Mute = "\xe74f"; + public const string BackSpaceQWERTY = "\xe750"; + public const string ReturnKey = "\xe751"; + public const string UpArrowShiftKey = "\xe752"; + public const string Cloud = "\xe753"; + public const string Flashlight = "\xe754"; + public const string RotationLock = "\xe755"; + public const string CommandPrompt = "\xe756"; + public const string SIPMove = "\xe759"; + public const string SIPUndock = "\xe75a"; + public const string SIPRedock = "\xe75b"; + public const string EraseTool = "\xe75c"; + public const string UnderscoreSpace = "\xe75d"; + public const string GripperTool = "\xe75e"; + public const string Dialpad = "\xe75f"; + public const string PageLeft = "\xe760"; + public const string PageRight = "\xe761"; + public const string MultiSelect = "\xe762"; + public const string KeyboardLeftHanded = "\xe763"; + public const string KeyboardRightHanded = "\xe764"; + public const string KeyboardClassic = "\xe765"; + public const string KeyboardSplit = "\xe766"; + public const string Volume = "\xe767"; + public const string Play = "\xe768"; + public const string Pause = "\xe769"; + public const string ChevronLeft = "\xe76b"; + public const string ChevronRight = "\xe76c"; + public const string InkingTool = "\xe76d"; + public const string Emoji2 = "\xe76e"; + public const string GripperBarHorizontal = "\xe76f"; + public const string System = "\xe770"; + public const string Personalize = "\xe771"; + public const string Devices = "\xe772"; + public const string SearchAndApps = "\xe773"; + public const string Globe = "\xe774"; + public const string TimeLanguage = "\xe775"; + public const string EaseOfAccess = "\xe776"; + public const string UpdateRestore = "\xe777"; + public const string HangUp = "\xe778"; + public const string ContactInfo = "\xe779"; + public const string Unpin = "\xe77a"; + public const string Contact = "\xe77b"; + public const string Memo = "\xe77c"; + public const string IncomingCall = "\xe77e"; + public const string Paste = "\xe77f"; + public const string PhoneBook = "\xe780"; + public const string LEDLight = "\xe781"; + public const string Error = "\xe783"; + public const string GripperBarVertical = "\xe784"; + public const string Unlock = "\xe785"; + public const string Slideshow = "\xe786"; + public const string Calendar = "\xe787"; + public const string GripperResize = "\xe788"; + public const string Megaphone = "\xe789"; + public const string Trim = "\xe78a"; + public const string NewWindow = "\xe78b"; + public const string SaveLocal = "\xe78c"; + public const string Color = "\xe790"; + public const string DataSense = "\xe791"; + public const string SaveAs = "\xe792"; + public const string Light = "\xe793"; + public const string Effects = "\xe794"; + public const string AspectRatio = "\xe799"; + public const string Contrast = "\xe7a1"; + public const string DataSenseBar = "\xe7a5"; + public const string Redo = "\xe7a6"; + public const string Undo = "\xe7a7"; + public const string Crop = "\xe7a8"; + public const string PhotoCollection = "\xe7ac"; + public const string OpenWith = "\xe7aa"; + public const string Rotate = "\xe7ad"; + public const string RedEye = "\xe7b3"; + public const string SetlockScreen = "\xe7b5"; + public const string MapPin2 = "\xe7b7"; + public const string Package = "\xe7b8"; + public const string Warning = "\xe7ba"; + public const string ReadingList = "\xe7bc"; + public const string Education = "\xe7be"; + public const string ShoppingCart = "\xe7bf"; + public const string Train = "\xe7c0"; + public const string Flag = "\xe7c1"; + public const string Move = "\xe7c2"; + public const string Page = "\xe7c3"; + public const string TaskView = "\xe7c4"; + public const string BrowsePhotos = "\xe7c5"; + public const string HalfStarLeft = "\xe7c6"; + public const string HalfStarRight = "\xe7c7"; + public const string Record = "\xe7c8"; + public const string TouchPointer = "\xe7c9"; + public const string LangJPN = "\xe7de"; + public const string Ferry = "\xe7e3"; + public const string Highlight = "\xe7e6"; + public const string ActionCenterNotification = "\xe7e7"; + public const string PowerButton = "\xe7e8"; + public const string ResizeTouchNarrower = "\xe7ea"; + public const string ResizeTouchShorter = "\xe7eb"; + public const string DrivingMode = "\xe7ec"; + public const string RingerSilent = "\xe7ed"; + public const string OtherUser = "\xe7ee"; + public const string Admin = "\xe7ef"; + public const string CC = "\xe7f0"; + public const string SDCard = "\xe7f1"; + public const string CallForwarding = "\xe7f2"; + public const string SettingsDisplaySound = "\xe7f3"; + public const string TVMonitor = "\xe7f4"; + public const string Speakers = "\xe7f5"; + public const string Headphone = "\xe7f6"; + public const string DeviceLaptopPic = "\xe7f7"; + public const string DeviceLaptopNoPic = "\xe7f8"; + public const string DeviceMonitorRightPic = "\xe7f9"; + public const string DeviceMonitorLeftPic = "\xe7fa"; + public const string DeviceMonitorNoPic = "\xe7fb"; + public const string Game = "\xe7fc"; + public const string HorizontalTabKey = "\xe7fd"; + public const string StreetsideSplitMinimize = "\xe802"; + public const string StreetsideSplitExpand = "\xe803"; + public const string Car = "\xe804"; + public const string Walk = "\xe805"; + public const string Bus = "\xe806"; + public const string TiltUp = "\xe809"; + public const string TiltDown = "\xe80a"; + public const string CallControl = "\xe80b"; + public const string RotateMapRight = "\xe80c"; + public const string RotateMapLeft = "\xe80d"; + public const string Home = "\xe80f"; + public const string ParkingLocation = "\xe811"; + public const string MapCompassTop = "\xe812"; + public const string MapCompassBottom = "\xe813"; + public const string IncidentTriangle = "\xe814"; + public const string Touch = "\xe815"; + public const string MapDirections = "\xe816"; + public const string StartPoint = "\xe819"; + public const string StopPoint = "\xe81a"; + public const string EndPoint = "\xe81b"; + public const string History = "\xe81c"; + public const string Location = "\xe81d"; + public const string MapLayers = "\xe81e"; + public const string Accident = "\xe81f"; + public const string Work = "\xe821"; + public const string Construction = "\xe822"; + public const string Recent = "\xe823"; + public const string Bank = "\xe825"; + public const string DownloadMap = "\xe826"; + public const string InkingToolFill2 = "\xe829"; + public const string HighlightFill2 = "\xe82a"; + public const string EraseToolFill = "\xe82b"; + public const string EraseToolFill2 = "\xe82c"; + public const string Dictionary = "\xe82d"; + public const string DictionaryAdd = "\xe82e"; + public const string ToolTip = "\xe82f"; + public const string ChromeBack = "\xe830"; + public const string ProvisioningPackage = "\xe835"; + public const string AddRemoteDevice = "\xe836"; + public const string FolderOpen = "\xe838"; + public const string Ethernet = "\xe839"; + public const string ShareBroadband = "\xe83a"; + public const string DirectAccess = "\xe83b"; + public const string DialUp = "\xe83c"; + public const string DefenderApp = "\xe83d"; + public const string BatteryCharging9 = "\xe83e"; + public const string Battery10 = "\xe83f"; + public const string Pinned = "\xe840"; + public const string PinFill = "\xe841"; + public const string PinnedFill = "\xe842"; + public const string PeriodKey = "\xe843"; + public const string PuncKey = "\xe844"; + public const string RevToggleKey = "\xe845"; + public const string RightArrowKeyTime1 = "\xe846"; + public const string RightArrowKeyTime2 = "\xe847"; + public const string LeftQuote = "\xe848"; + public const string RightQuote = "\xe849"; + public const string DownShiftKey = "\xe84a"; + public const string UpShiftKey = "\xe84b"; + public const string PuncKey0 = "\xe84c"; + public const string PuncKeyLeftBottom = "\xe84d"; + public const string RightArrowKeyTime3 = "\xe84e"; + public const string RightArrowKeyTime4 = "\xe84f"; + public const string Battery0 = "\xe850"; + public const string Battery1 = "\xe851"; + public const string Battery2 = "\xe852"; + public const string Battery3 = "\xe853"; + public const string Battery4 = "\xe854"; + public const string Battery5 = "\xe855"; + public const string Battery6 = "\xe856"; + public const string Battery7 = "\xe857"; + public const string Battery8 = "\xe858"; + public const string Battery9 = "\xe859"; + public const string BatteryCharging0 = "\xe85a"; + public const string BatteryCharging1 = "\xe85b"; + public const string BatteryCharging2 = "\xe85c"; + public const string BatteryCharging3 = "\xe85d"; + public const string BatteryCharging4 = "\xe85e"; + public const string BatteryCharging5 = "\xe85f"; + public const string BatteryCharging6 = "\xe860"; + public const string BatteryCharging7 = "\xe861"; + public const string BatteryCharging8 = "\xe862"; + public const string BatterySaver0 = "\xe863"; + public const string BatterySaver1 = "\xe864"; + public const string BatterySaver2 = "\xe865"; + public const string BatterySaver3 = "\xe866"; + public const string BatterySaver4 = "\xe867"; + public const string BatterySaver5 = "\xe868"; + public const string BatterySaver6 = "\xe869"; + public const string BatterySaver7 = "\xe86a"; + public const string BatterySaver8 = "\xe86b"; + public const string SignalBars1 = "\xe86c"; + public const string SignalBars2 = "\xe86d"; + public const string SignalBars3 = "\xe86e"; + public const string SignalBars4 = "\xe86f"; + public const string SignalBars5 = "\xe870"; + public const string SignalNotConnected = "\xe871"; + public const string Wifi1 = "\xe872"; + public const string Wifi2 = "\xe873"; + public const string Wifi3 = "\xe874"; + public const string MobSIMLock = "\xe875"; + public const string MobSIMMissing = "\xe876"; + public const string Vibrate = "\xe877"; + public const string RoamingInternational = "\xe878"; + public const string RoamingDomestic = "\xe879"; + public const string CallForwardInternational = "\xe87a"; + public const string CallForwardRoaming = "\xe87b"; + public const string JpnRomanji = "\xe87c"; + public const string JpnRomanjiLock = "\xe87d"; + public const string JpnRomanjiShift = "\xe87e"; + public const string JpnRomanjiShiftLock = "\xe87f"; + public const string StatusDataTransfer = "\xe880"; + public const string StatusDataTransferVPN = "\xe881"; + public const string StatusDualSIM2 = "\xe882"; + public const string StatusDualSIM2VPN = "\xe883"; + public const string StatusDualSIM1 = "\xe884"; + public const string StatusDualSIM1VPN = "\xe885"; + public const string StatusSGLTE = "\xe886"; + public const string StatusSGLTECell = "\xe887"; + public const string StatusSGLTEDataVPN = "\xe888"; + public const string StatusVPN = "\xe889"; + public const string WifiHotspot = "\xe88a"; + public const string LanguageKor = "\xe88b"; + public const string LanguageCht = "\xe88c"; + public const string LanguageChs = "\xe88d"; + public const string USB = "\xe88e"; + public const string InkingToolFill = "\xe88f"; + public const string View = "\xe890"; + public const string HighlightFill = "\xe891"; + public const string Previous = "\xe892"; + public const string Next = "\xe893"; + public const string Clear = "\xe894"; + public const string Sync = "\xe895"; + public const string Download = "\xe896"; + public const string Help = "\xe897"; + public const string Upload = "\xe898"; + public const string Emoji = "\xe899"; + public const string TwoPage = "\xe89a"; + public const string LeaveChat = "\xe89b"; + public const string MailForward = "\xe89c"; + public const string RotateCamera = "\xe89e"; + public const string ClosePane = "\xe89f"; + public const string OpenPane = "\xe8a0"; + public const string PreviewLink = "\xe8a1"; + public const string AttachCamera = "\xe8a2"; + public const string ZoomIn = "\xe8a3"; + public const string Bookmarks = "\xe8a4"; + public const string Document = "\xe8a5"; + public const string ProtectedDocument = "\xe8a6"; + public const string OpenInNewWindow = "\xe8a7"; + public const string MailFill = "\xe8a8"; + public const string ViewAll = "\xe8a9"; + public const string VideoChat = "\xe8aa"; + public const string Switch = "\xe8ab"; + public const string Rename = "\xe8ac"; + public const string Go = "\xe8ad"; + public const string SurfaceHub = "\xe8ae"; + public const string Remote = "\xe8af"; + public const string Click = "\xe8b0"; + public const string Shuffle = "\xe8b1"; + public const string Movies = "\xe8b2"; + public const string SelectAll = "\xe8b3"; + public const string Orientation = "\xe8b4"; + public const string Import = "\xe8b5"; + public const string ImportAll = "\xe8b6"; + public const string Folder = "\xe8b7"; + public const string Webcam = "\xe8b8"; + public const string Picture = "\xe8b9"; + public const string Caption = "\xe8ba"; + public const string ChromeClose = "\xe8bb"; + public const string ShowResults = "\xe8bc"; + public const string Message = "\xe8bd"; + public const string Leaf = "\xe8be"; + public const string CalendarDay = "\xe8bf"; + public const string CalendarWeek = "\xe8c0"; + public const string Characters = "\xe8c1"; + public const string MailReplyAll = "\xe8c2"; + public const string Read = "\xe8c3"; + public const string ShowBcc = "\xe8c4"; + public const string HideBcc = "\xe8c5"; + public const string Cut = "\xe8c6"; + public const string PaymentCard = "\xe8c7"; + public const string Copy = "\xe8c8"; + public const string Important = "\xe8c9"; + public const string MailReply = "\xe8ca"; + public const string Sort = "\xe8cb"; + public const string MobileTablet = "\xe8cc"; + public const string DisconnectDrive = "\xe8cd"; + public const string MapDrive = "\xe8ce"; + public const string ContactPresence = "\xe8cf"; + public const string Priority = "\xe8d0"; + public const string GotoToday = "\xe8d1"; + public const string Font = "\xe8d2"; + public const string FontColor = "\xe8d3"; + public const string Contact2 = "\xe8d4"; + public const string FolderFill = "\xe8d5"; + public const string Audio = "\xe8d6"; + public const string Permissions = "\xe8d7"; + public const string DisableUpdates = "\xe8d8"; + public const string Unfavorite = "\xe8d9"; + public const string OpenLocal = "\xe8da"; + public const string Italic = "\xe8db"; + public const string Underline = "\xe8dc"; + public const string Bold = "\xe8dd"; + public const string MoveToFolder = "\xe8de"; + public const string LikeDislike = "\xe8df"; + public const string Dislike = "\xe8e0"; + public const string Like = "\xe8e1"; + public const string AlignRight = "\xe8e2"; + public const string AlignCenter = "\xe8e3"; + public const string AlignLeft = "\xe8e4"; + public const string OpenFile = "\xe8e5"; + public const string ClearSelection = "\xe8e6"; + public const string FontDecrease = "\xe8e7"; + public const string FontIncrease = "\xe8e8"; + public const string FontSize = "\xe8e9"; + public const string CellPhone = "\xe8ea"; + public const string Reshare = "\xe8eb"; + public const string Tag = "\xe8ec"; + public const string RepeatOne = "\xe8ed"; + public const string RepeatAll = "\xe8ee"; + public const string Calculator = "\xe8ef"; + public const string Directions = "\xe8f0"; + public const string Library = "\xe8f1"; + public const string ChatBubbles = "\xe8f2"; + public const string PostUpdate = "\xe8f3"; + public const string NewFolder = "\xe8f4"; + public const string CalendarReply = "\xe8f5"; + public const string UnsyncFolder = "\xe8f6"; + public const string SyncFolder = "\xe8f7"; + public const string BlockContact = "\xe8f8"; + public const string SwitchApps = "\xe8f9"; + public const string AddFriend = "\xe8fa"; + public const string Accept = "\xe8fb"; + public const string GoToStart = "\xe8fc"; + public const string BulletedList = "\xe8fd"; + public const string Scan = "\xe8fe"; + public const string Preview = "\xe8ff"; + public const string Group = "\xe902"; + public const string ZeroBars = "\xe904"; + public const string OneBar = "\xe905"; + public const string TwoBars = "\xe906"; + public const string ThreeBars = "\xe907"; + public const string FourBars = "\xe908"; + public const string World = "\xe909"; + public const string Comment = "\xe90a"; + public const string MusicInfo = "\xe90b"; + public const string DockLeft = "\xe90c"; + public const string DockRight = "\xe90d"; + public const string DockBottom = "\xe90e"; + public const string Repair = "\xe90f"; + public const string Accounts = "\xe910"; + public const string DullSound = "\xe911"; + public const string Manage = "\xe912"; + public const string Street = "\xe913"; + public const string Printer3D = "\xe914"; + public const string RadioBullet = "\xe915"; + public const string Stopwatch = "\xe916"; + public const string Photo = "\xe91b"; + public const string ActionCenter = "\xe91c"; + public const string FullCircleMask = "\xe91f"; + public const string ChromeMinimize = "\xe921"; + public const string ChromeMaximize = "\xe922"; + public const string ChromeRestore = "\xe923"; + public const string Annotation = "\xe924"; + public const string BackSpaceQWERTYSm = "\xe925"; + public const string BackSpaceQWERTYMd = "\xe926"; + public const string Swipe = "\xe927"; + public const string Fingerprint = "\xe928"; + public const string Handwriting = "\xe929"; + public const string ChromeBackToWindow = "\xe92c"; + public const string ChromeFullScreen = "\xe92d"; + public const string KeyboardStandard = "\xe92e"; + public const string KeyboardDismiss = "\xe92f"; + public const string Completed = "\xe930"; + public const string ChromeAnnotate = "\xe931"; + public const string Label = "\xe932"; + public const string IBeam = "\xe933"; + public const string IBeamOutline = "\xe934"; + public const string FlickDown = "\xe935"; + public const string FlickUp = "\xe936"; + public const string FlickLeft = "\xe937"; + public const string FlickRight = "\xe938"; + public const string FeedbackApp = "\xe939"; + public const string MusicAlbum = "\xe93c"; + public const string Streaming = "\xe93e"; + public const string Code = "\xe943"; + public const string ReturnToWindow = "\xe944"; + public const string LightningBolt = "\xe945"; + public const string Info = "\xe946"; + public const string CalculatorMultiply = "\xe947"; + public const string CalculatorAddition = "\xe948"; + public const string CalculatorSubtract = "\xe949"; + public const string CalculatorDivide = "\xe94a"; + public const string CalculatorSquareroot = "\xe94b"; + public const string CalculatorPercentage = "\xe94c"; + public const string CalculatorNegate = "\xe94d"; + public const string CalculatorEqualTo = "\xe94e"; + public const string CalculatorBackspace = "\xe94f"; + public const string Component = "\xe950"; + public const string DMC = "\xe951"; + public const string Dock = "\xe952"; + public const string MultimediaDMS = "\xe953"; + public const string MultimediaDVR = "\xe954"; + public const string MultimediaPMP = "\xe955"; + public const string PrintfaxPrinterFile = "\xe956"; + public const string Sensor = "\xe957"; + public const string StorageOptical = "\xe958"; + public const string Communications = "\xe95a"; + public const string Headset = "\xe95b"; + public const string Projector = "\xe95d"; + public const string Health = "\xe95e"; + public const string Wire = "\xe95f"; + public const string Webcam2 = "\xe960"; + public const string Input = "\xe961"; + public const string Mouse = "\xe962"; + public const string Smartcard = "\xe963"; + public const string SmartcardVirtual = "\xe964"; + public const string MediaStorageTower = "\xe965"; + public const string ReturnKeySm = "\xe966"; + public const string GameConsole = "\xe967"; + public const string Network = "\xe968"; + public const string StorageNetworkWireless = "\xe969"; + public const string StorageTape = "\xe96a"; + public const string ChevronUpSmall = "\xe96d"; + public const string ChevronDownSmall = "\xe96e"; + public const string ChevronLeftSmall = "\xe96f"; + public const string ChevronRightSmall = "\xe970"; + public const string ChevronUpMed = "\xe971"; + public const string ChevronDownMed = "\xe972"; + public const string ChevronLeftMed = "\xe973"; + public const string ChevronRightMed = "\xe974"; + public const string Devices2 = "\xe975"; + public const string ExpandTile = "\xe976"; + public const string PC1 = "\xe977"; + public const string PresenceChicklet = "\xe978"; + public const string PresenceChickletVideo = "\xe979"; + public const string Reply = "\xe97a"; + public const string SetTile = "\xe97b"; + public const string Type = "\xe97c"; + public const string Korean = "\xe97d"; + public const string HalfAlpha = "\xe97e"; + public const string FullAlpha = "\xe97f"; + public const string Key12On = "\xe980"; + public const string ChineseChangjie = "\xe981"; + public const string QWERTYOn = "\xe982"; + public const string QWERTYOff = "\xe983"; + public const string ChineseQuick = "\xe984"; + public const string Japanese = "\xe985"; + public const string FullHiragana = "\xe986"; + public const string FullKatakana = "\xe987"; + public const string HalfKatakana = "\xe988"; + public const string ChineseBoPoMoFo = "\xe989"; + public const string ChinesePinyin = "\xe98a"; + public const string ConstructionCone = "\xe98f"; + public const string XboxOneConsole = "\xe990"; + public const string Volume0 = "\xe992"; + public const string Volume1 = "\xe993"; + public const string Volume2 = "\xe994"; + public const string Volume3 = "\xe995"; + public const string BatteryUnknown = "\xe996"; + public const string WifiAttentionOverlay = "\xe998"; + public const string Robot = "\xe99a"; + public const string TapAndSend = "\xe9a1"; + public const string FitPage = "\xe9a6"; + public const string PasswordKeyShow = "\xe9a8"; + public const string PasswordKeyHide = "\xe9a9"; + public const string BidiLtr = "\xe9aa"; + public const string BidiRtl = "\xe9ab"; + public const string ForwardSm = "\xe9ac"; + public const string CommaKey = "\xe9ad"; + public const string DashKey = "\xe9ae"; + public const string DullSoundKey = "\xe9af"; + public const string HalfDullSound = "\xe9b0"; + public const string RightDoubleQuote = "\xe9b1"; + public const string LeftDoubleQuote = "\xe9b2"; + public const string PuncKeyRightBottom = "\xe9b3"; + public const string PuncKey1 = "\xe9b4"; + public const string PuncKey2 = "\xe9b5"; + public const string PuncKey3 = "\xe9b6"; + public const string PuncKey4 = "\xe9b7"; + public const string PuncKey5 = "\xe9b8"; + public const string PuncKey6 = "\xe9b9"; + public const string PuncKey9 = "\xe9ba"; + public const string PuncKey7 = "\xe9bb"; + public const string PuncKey8 = "\xe9bc"; + public const string Frigid = "\xe9ca"; + public const string Unknown = "\xe9ce"; + public const string AreaChart = "\xe9d2"; + public const string CheckList = "\xe9d5"; + public const string Diagnostic = "\xe9d9"; + public const string Equalizer = "\xe9e9"; + public const string Process = "\xe9f3"; + public const string Processing = "\xe9f5"; + public const string ReportDocument = "\xe9f9"; + public const string VideoSolid = "\xea0c"; + public const string MixedMediaBadge = "\xea0d"; + public const string DisconnectDisplay = "\xea14"; + public const string Shield = "\xea18"; + public const string Info2 = "\xea1f"; + public const string ActionCenterAsterisk = "\xea21"; + public const string Beta = "\xea24"; + public const string SaveCopy = "\xea35"; + public const string List = "\xea37"; + public const string Asterisk = "\xea38"; + public const string ErrorBadge = "\xea39"; + public const string CircleRing = "\xea3a"; + public const string CircleFill = "\xea3b"; + public const string MergeCall = "\xea3c"; + public const string PrivateCall = "\xea3d"; + public const string Record2 = "\xea3f"; + public const string AllAppsMirrored = "\xea40"; + public const string BookmarksMirrored = "\xea41"; + public const string BulletedListMirrored = "\xea42"; + public const string CallForwardInternationalMirrored = "\xea43"; + public const string CallForwardRoamingMirrored = "\xea44"; + public const string ChromeBackMirrored = "\xea47"; + public const string ClearSelectionMirrored = "\xea48"; + public const string ClosePaneMirrored = "\xea49"; + public const string ContactInfoMirrored = "\xea4a"; + public const string DockRightMirrored = "\xea4b"; + public const string DockLeftMirrored = "\xea4c"; + public const string ExpandTileMirrored = "\xea4e"; + public const string GoMirrored = "\xea4f"; + public const string GripperResizeMirrored = "\xea50"; + public const string HelpMirrored = "\xea51"; + public const string ImportMirrored = "\xea52"; + public const string ImportAllMirrored = "\xea53"; + public const string LeaveChatMirrored = "\xea54"; + public const string ListMirrored = "\xea55"; + public const string MailForwardMirrored = "\xea56"; + public const string MailReplyMirrored = "\xea57"; + public const string MailReplyAllMirrored = "\xea58"; + public const string OpenPaneMirrored = "\xea5b"; + public const string OpenWithMirrored = "\xea5c"; + public const string ParkingLocationMirrored = "\xea5e"; + public const string ResizeMouseMediumMirrored = "\xea5f"; + public const string ResizeMouseSmallMirrored = "\xea60"; + public const string ResizeMouseTallMirrored = "\xea61"; + public const string ResizeTouchNarrowerMirrored = "\xea62"; + public const string SendMirrored = "\xea63"; + public const string SendFillMirrored = "\xea64"; + public const string ShowResultsMirrored = "\xea65"; + public const string Media = "\xea69"; + public const string SyncError = "\xea6a"; + public const string Devices3 = "\xea6c"; + public const string SlowMotionOn = "\xea79"; + public const string Lightbulb = "\xea80"; + public const string StatusCircle = "\xea81"; + public const string StatusTriangle = "\xea82"; + public const string StatusError = "\xea83"; + public const string StatusWarning = "\xea84"; + public const string Puzzle = "\xea86"; + public const string CalendarSolid = "\xea89"; + public const string HomeSolid = "\xea8a"; + public const string ParkingLocationSolid = "\xea8b"; + public const string ContactSolid = "\xea8c"; + public const string ConstructionSolid = "\xea8d"; + public const string AccidentSolid = "\xea8e"; + public const string Ringer = "\xea8f"; + public const string PDF = "\xea90"; + public const string ThoughtBubble = "\xea91"; + public const string HeartBroken = "\xea92"; + public const string BatteryCharging10 = "\xea93"; + public const string BatterySaver9 = "\xea94"; + public const string BatterySaver10 = "\xea95"; + public const string CallForwardingMirrored = "\xea97"; + public const string MultiSelectMirrored = "\xea98"; + public const string Broom = "\xea99"; + public const string ForwardCall = "\xeac2"; + public const string Trackers = "\xeadf"; + public const string Market = "\xeafc"; + public const string PieSingle = "\xeb05"; + public const string StockDown = "\xeb0f"; + public const string StockUp = "\xeb11"; + public const string Design = "\xeb3c"; + public const string Website = "\xeb41"; + public const string Drop = "\xeb42"; + public const string Radar = "\xeb44"; + public const string BusSolid = "\xeb47"; + public const string FerrySolid = "\xeb48"; + public const string StartPointSolid = "\xeb49"; + public const string StopPointSolid = "\xeb4a"; + public const string EndPointSolid = "\xeb4b"; + public const string AirplaneSolid = "\xeb4c"; + public const string TrainSolid = "\xeb4d"; + public const string WorkSolid = "\xeb4e"; + public const string ReminderFill = "\xeb4f"; + public const string Reminder = "\xeb50"; + public const string Heart = "\xeb51"; + public const string HeartFill = "\xeb52"; + public const string EthernetError = "\xeb55"; + public const string EthernetWarning = "\xeb56"; + public const string StatusConnecting1 = "\xeb57"; + public const string StatusConnecting2 = "\xeb58"; + public const string StatusUnsecure = "\xeb59"; + public const string WifiError0 = "\xeb5a"; + public const string WifiError1 = "\xeb5b"; + public const string WifiError2 = "\xeb5c"; + public const string WifiError3 = "\xeb5d"; + public const string WifiError4 = "\xeb5e"; + public const string WifiWarning0 = "\xeb5f"; + public const string WifiWarning1 = "\xeb60"; + public const string WifiWarning2 = "\xeb61"; + public const string WifiWarning3 = "\xeb62"; + public const string WifiWarning4 = "\xeb63"; + public const string Devices4 = "\xeb66"; + public const string NUIIris = "\xeb67"; + public const string NUIFace = "\xeb68"; + public const string GatewayRouter = "\xeb77"; + public const string EditMirrored = "\xeb7e"; + public const string NUIFPStartSlideHand = "\xeb82"; + public const string NUIFPStartSlideAction = "\xeb83"; + public const string NUIFPContinueSlideHand = "\xeb84"; + public const string NUIFPContinueSlideAction = "\xeb85"; + public const string NUIFPRollRightHand = "\xeb86"; + public const string NUIFPRollRightHandAction = "\xeb87"; + public const string NUIFPRollLeftHand = "\xeb88"; + public const string NUIFPRollLeftAction = "\xeb89"; + public const string NUIFPPressHand = "\xeb8a"; + public const string NUIFPPressAction = "\xeb8b"; + public const string NUIFPPressRepeatHand = "\xeb8c"; + public const string NUIFPPressRepeatAction = "\xeb8d"; + public const string StatusErrorFull = "\xeb90"; + public const string TaskViewExpanded = "\xeb91"; + public const string Certificate = "\xeb95"; + public const string BackSpaceQWERTYLg = "\xeb96"; + public const string ReturnKeyLg = "\xeb97"; + public const string FastForward = "\xeb9d"; + public const string Rewind = "\xeb9e"; + public const string Photo2 = "\xeb9f"; + public const string MobBattery0 = "\xeba0"; + public const string MobBattery1 = "\xeba1"; + public const string MobBattery2 = "\xeba2"; + public const string MobBattery3 = "\xeba3"; + public const string MobBattery4 = "\xeba4"; + public const string MobBattery5 = "\xeba5"; + public const string MobBattery6 = "\xeba6"; + public const string MobBattery7 = "\xeba7"; + public const string MobBattery8 = "\xeba8"; + public const string MobBattery9 = "\xeba9"; + public const string MobBattery10 = "\xebaa"; + public const string MobBatteryCharging0 = "\xebab"; + public const string MobBatteryCharging1 = "\xebac"; + public const string MobBatteryCharging2 = "\xebad"; + public const string MobBatteryCharging3 = "\xebae"; + public const string MobBatteryCharging4 = "\xebaf"; + public const string MobBatteryCharging5 = "\xebb0"; + public const string MobBatteryCharging6 = "\xebb1"; + public const string MobBatteryCharging7 = "\xebb2"; + public const string MobBatteryCharging8 = "\xebb3"; + public const string MobBatteryCharging9 = "\xebb4"; + public const string MobBatteryCharging10 = "\xebb5"; + public const string MobBatterySaver0 = "\xebb6"; + public const string MobBatterySaver1 = "\xebb7"; + public const string MobBatterySaver2 = "\xebb8"; + public const string MobBatterySaver3 = "\xebb9"; + public const string MobBatterySaver4 = "\xebba"; + public const string MobBatterySaver5 = "\xebbb"; + public const string MobBatterySaver6 = "\xebbc"; + public const string MobBatterySaver7 = "\xebbd"; + public const string MobBatterySaver8 = "\xebbe"; + public const string MobBatterySaver9 = "\xebbf"; + public const string MobBatterySaver10 = "\xebc0"; + public const string DictionaryCloud = "\xebc3"; + public const string ResetDrive = "\xebc4"; + public const string VolumeBars = "\xebc5"; + public const string Project = "\xebc6"; + public const string AdjustHologram = "\xebd2"; + public const string CloudDownload = "\xebd3"; + public const string MobWifiCallBars = "\xebd4"; + public const string MobWifiCall0 = "\xebd5"; + public const string MobWifiCall1 = "\xebd6"; + public const string MobWifiCall2 = "\xebd7"; + public const string MobWifiCall3 = "\xebd8"; + public const string MobWifiCall4 = "\xebd9"; + public const string Family = "\xebda"; + public const string LockFeedback = "\xebdb"; + public const string DeviceDiscovery = "\xebde"; + public const string WindDirection = "\xebe6"; + public const string RightArrowKeyTime0 = "\xebe7"; + public const string Bug = "\xebe8"; + public const string TabletMode = "\xebfc"; + public const string StatusCircleLeft = "\xebfd"; + public const string StatusTriangleLeft = "\xebfe"; + public const string StatusErrorLeft = "\xebff"; + public const string StatusWarningLeft = "\xec00"; + public const string MobBatteryUnknown = "\xec02"; + public const string NetworkTower = "\xec05"; + public const string CityNext = "\xec06"; + public const string CityNext2 = "\xec07"; + public const string Courthouse = "\xec08"; + public const string Groceries = "\xec09"; + public const string Sustainable = "\xec0a"; + public const string BuildingEnergy = "\xec0b"; + public const string ToggleFilled = "\xec11"; + public const string ToggleBorder = "\xec12"; + public const string SliderThumb = "\xec13"; + public const string ToggleThumb = "\xec14"; + public const string MiracastLogoSmall = "\xec15"; + public const string MiracastLogoLarge = "\xec16"; + public const string PLAP = "\xec19"; + public const string Badge = "\xec1b"; + public const string SignalRoaming = "\xec1e"; + public const string MobileLocked = "\xec20"; + public const string InsiderHubApp = "\xec24"; + public const string PersonalFolder = "\xec25"; + public const string HomeGroup = "\xec26"; + public const string MyNetwork = "\xec27"; + public const string KeyboardFull = "\xec31"; + public const string Cafe = "\xec32"; + public const string MobSignal1 = "\xec37"; + public const string MobSignal2 = "\xec38"; + public const string MobSignal3 = "\xec39"; + public const string MobSignal4 = "\xec3a"; + public const string MobSignal5 = "\xec3b"; + public const string MobWifi1 = "\xec3c"; + public const string MobWifi2 = "\xec3d"; + public const string MobWifi3 = "\xec3e"; + public const string MobWifi4 = "\xec3f"; + public const string MobAirplane = "\xec40"; + public const string MobBluetooth = "\xec41"; + public const string MobActionCenter = "\xec42"; + public const string MobLocation = "\xec43"; + public const string MobWifiHotspot = "\xec44"; + public const string LanguageJpn = "\xec45"; + public const string MobQuietHours = "\xec46"; + public const string MobDrivingMode = "\xec47"; + public const string SpeedOff = "\xec48"; + public const string SpeedMedium = "\xec49"; + public const string SpeedHigh = "\xec4a"; + public const string ThisPC = "\xec4e"; + public const string MusicNote = "\xec4f"; + public const string FileExplorer = "\xec50"; + public const string FileExplorerApp = "\xec51"; + public const string LeftArrowKeyTime0 = "\xec52"; + public const string MicOff = "\xec54"; + public const string MicSleep = "\xec55"; + public const string MicError = "\xec56"; + public const string PlaybackRate1x = "\xec57"; + public const string PlaybackRateOther = "\xec58"; + public const string CashDrawer = "\xec59"; + public const string BarcodeScanner = "\xec5a"; + public const string ReceiptPrinter = "\xec5b"; + public const string MagStripeReader = "\xec5c"; + public const string CompletedSolid = "\xec61"; + public const string CompanionApp = "\xec64"; + public const string Favicon2 = "\xec6c"; + public const string SwipeRevealArt = "\xec6d"; + public const string MicOn = "\xec71"; + public const string MicClipping = "\xec72"; + public const string TabletSelected = "\xec74"; + public const string MobileSelected = "\xec75"; + public const string LaptopSelected = "\xec76"; + public const string TVMonitorSelected = "\xec77"; + public const string DeveloperTools = "\xec7a"; + public const string MobCallForwarding = "\xec7e"; + public const string MobCallForwardingMirrored = "\xec7f"; + public const string BodyCam = "\xec80"; + public const string PoliceCar = "\xec81"; + public const string Draw = "\xec87"; + public const string DrawSolid = "\xec88"; + public const string LowerBrightness = "\xec8a"; + public const string ScrollUpDown = "\xec8f"; + public const string Uninstall = "\xec91"; + public const string DateTime = "\xec92"; + public const string HoloLens = "\xec94"; + public const string CloudNotSynced = "\xec9c"; + public const string Tiles = "\xeca5"; + public const string PartyLeader = "\xeca7"; + public const string AppIconDefault = "\xecaa"; + public const string Calories = "\xecad"; + public const string POI = "\xecaf"; + public const string BandBattery0 = "\xecb9"; + public const string BandBattery1 = "\xecba"; + public const string BandBattery2 = "\xecbb"; + public const string BandBattery3 = "\xecbc"; + public const string BandBattery4 = "\xecbd"; + public const string BandBattery5 = "\xecbe"; + public const string BandBattery6 = "\xecbf"; + public const string AddSurfaceHub = "\xecc4"; + public const string DevUpdate = "\xecc5"; + public const string Unit = "\xecc6"; + public const string AddTo = "\xecc8"; + public const string RemoveFrom = "\xecc9"; + public const string RadioBtnOff = "\xecca"; + public const string RadioBtnOn = "\xeccb"; + public const string RadioBullet2 = "\xeccc"; + public const string ExploreContent = "\xeccd"; + public const string Blocked2 = "\xece4"; + public const string ScrollMode = "\xece7"; + public const string ZoomMode = "\xece8"; + public const string PanMode = "\xece9"; + public const string WiredUSB = "\xecf0"; + public const string WirelessUSB = "\xecf1"; + public const string USBSafeConnect = "\xecf3"; + public const string ActionCenterNotificationMirrored = "\xed0c"; + public const string ActionCenterMirrored = "\xed0d"; + public const string SubscriptionAdd = "\xed0e"; + public const string ResetDevice = "\xed10"; + public const string SubscriptionAddMirrored = "\xed11"; + public const string QRCode = "\xed14"; + public const string Feedback = "\xed15"; + public const string Hide = "\xed1a"; + public const string Subtitles = "\xed1e"; + public const string SubtitlesAudio = "\xed1f"; + public const string OpenFolderHorizontal = "\xed25"; + public const string CalendarMirrored = "\xed28"; + public const string MobeSIM = "\xed2a"; + public const string MobeSIMNoProfile = "\xed2b"; + public const string MobeSIMLocked = "\xed2c"; + public const string MobeSIMBusy = "\xed2d"; + public const string SignalError = "\xed2e"; + public const string StreamingEnterprise = "\xed2f"; + public const string Headphone0 = "\xed30"; + public const string Headphone1 = "\xed31"; + public const string Headphone2 = "\xed32"; + public const string Headphone3 = "\xed33"; + public const string Apps = "\xed35"; + public const string KeyboardBrightness = "\xed39"; + public const string KeyboardLowerBrightness = "\xed3a"; + public const string SkipBack10 = "\xed3c"; + public const string SkipForward30 = "\xed3d"; + public const string TreeFolderFolder = "\xed41"; + public const string TreeFolderFolderFill = "\xed42"; + public const string TreeFolderFolderOpen = "\xed43"; + public const string TreeFolderFolderOpenFill = "\xed44"; + public const string MultimediaDMP = "\xed47"; + public const string KeyboardOneHanded = "\xed4c"; + public const string Narrator = "\xed4d"; + public const string EmojiTabPeople = "\xed53"; + public const string EmojiTabSmilesAnimals = "\xed54"; + public const string EmojiTabCelebrationObjects = "\xed55"; + public const string EmojiTabFoodPlants = "\xed56"; + public const string EmojiTabTransitPlaces = "\xed57"; + public const string EmojiTabSymbols = "\xed58"; + public const string EmojiTabTextSmiles = "\xed59"; + public const string EmojiTabFavorites = "\xed5a"; + public const string EmojiSwatch = "\xed5b"; + public const string ConnectApp = "\xed5c"; + public const string CompanionDeviceFramework = "\xed5d"; + public const string Ruler = "\xed5e"; + public const string FingerInking = "\xed5f"; + public const string StrokeErase = "\xed60"; + public const string PointErase = "\xed61"; + public const string ClearAllInk = "\xed62"; + public const string Pencil = "\xed63"; + public const string Marker = "\xed64"; + public const string InkingCaret = "\xed65"; + public const string InkingColorOutline = "\xed66"; + public const string InkingColorFill = "\xed67"; + public const string HardDrive = "\xeda2"; + public const string NetworkAdapter = "\xeda3"; + public const string Touchscreen = "\xeda4"; + public const string NetworkPrinter = "\xeda5"; + public const string CloudPrinter = "\xeda6"; + public const string KeyboardShortcut = "\xeda7"; + public const string BrushSize = "\xeda8"; + public const string NarratorForward = "\xeda9"; + public const string NarratorForwardMirrored = "\xedaa"; + public const string SyncBadge12 = "\xedab"; + public const string RingerBadge12 = "\xedac"; + public const string AsteriskBadge12 = "\xedad"; + public const string ErrorBadge12 = "\xedae"; + public const string CircleRingBadge12 = "\xedaf"; + public const string CircleFillBadge12 = "\xedb0"; + public const string ImportantBadge12 = "\xedb1"; + public const string MailBadge12 = "\xedb3"; + public const string PauseBadge12 = "\xedb4"; + public const string PlayBadge12 = "\xedb5"; + public const string PenWorkspace = "\xedc6"; + public const string CaretLeft8 = "\xedd5"; + public const string CaretRight8 = "\xedd6"; + public const string CaretUp8 = "\xedd7"; + public const string CaretDown8 = "\xedd8"; + public const string CaretLeftSolid8 = "\xedd9"; + public const string CaretRightSolid8 = "\xedda"; + public const string CaretUpSolid8 = "\xeddb"; + public const string CaretDownSolid8 = "\xeddc"; + public const string Strikethrough = "\xede0"; + public const string Export = "\xede1"; + public const string ExportMirrored = "\xede2"; + public const string ButtonMenu = "\xede3"; + public const string CloudSearch = "\xede4"; + public const string PinyinIMELogo = "\xede5"; + public const string CalligraphyPen = "\xedfb"; + public const string ReplyMirrored = "\xee35"; + public const string LockscreenDesktop = "\xee3f"; + public const string TaskViewSettings = "\xee40"; + public const string MiniExpand2Mirrored = "\xee47"; + public const string MiniContract2Mirrored = "\xee49"; + public const string Play36 = "\xee4a"; + public const string PenPalette = "\xee56"; + public const string GuestUser = "\xee57"; + public const string SettingsBattery = "\xee63"; + public const string TaskbarPhone = "\xee64"; + public const string LockScreenGlance = "\xee65"; + public const string GenericScan = "\xee6f"; + public const string ImageExport = "\xee71"; + public const string WifiEthernet = "\xee77"; + public const string ActionCenterQuiet = "\xee79"; + public const string ActionCenterQuietNotification = "\xee7a"; + public const string TrackersMirrored = "\xee92"; + public const string DateTimeMirrored = "\xee93"; + public const string Wheel = "\xee94"; + public const string VirtualMachineGroup = "\xeea3"; + public const string ButtonView2 = "\xeeca"; + public const string PenWorkspaceMirrored = "\xef15"; + public const string PenPaletteMirrored = "\xef16"; + public const string StrokeEraseMirrored = "\xef17"; + public const string PointEraseMirrored = "\xef18"; + public const string ClearAllInkMirrored = "\xef19"; + public const string BackgroundToggle = "\xef1f"; + public const string Marquee = "\xef20"; + public const string ChromeCloseContrast = "\xef2c"; + public const string ChromeMinimizeContrast = "\xef2d"; + public const string ChromeMaximizeContrast = "\xef2e"; + public const string ChromeRestoreContrast = "\xef2f"; + public const string TrafficLight = "\xef31"; + public const string Replay = "\xef3b"; + public const string Eyedropper = "\xef3c"; + public const string LineDisplay = "\xef3d"; + public const string PINPad = "\xef3e"; + public const string SignatureCapture = "\xef3f"; + public const string ChipCardCreditCardReader = "\xef40"; + public const string MarketDown = "\xef42"; + public const string PlayerSettings = "\xef58"; + public const string LandscapeOrientation = "\xef6b"; + public const string Flow = "\xef90"; + public const string Touchpad = "\xefa5"; + public const string Speech = "\xefa9"; + public const string KnowledgeArticle = "\xf000"; + public const string Relationship = "\xf003"; + public const string ZipFolder = "\xf012"; + public const string DefaultAPN = "\xf080"; + public const string UserAPN = "\xf081"; + public const string DoublePinyin = "\xf085"; + public const string BlueLight = "\xf08c"; + public const string CaretSolidLeft = "\xf08d"; + public const string CaretSolidDown = "\xf08e"; + public const string CaretSolidRight = "\xf08f"; + public const string CaretSolidUp = "\xf090"; + public const string ButtonA = "\xf093"; + public const string ButtonB = "\xf094"; + public const string ButtonY = "\xf095"; + public const string ButtonX = "\xf096"; + public const string ArrowUp8 = "\xf0ad"; + public const string ArrowDown8 = "\xf0ae"; + public const string ArrowRight8 = "\xf0af"; + public const string ArrowLeft8 = "\xf0b0"; + public const string QuarentinedItems = "\xf0b2"; + public const string QuarentinedItemsMirrored = "\xf0b3"; + public const string Protractor = "\xf0b4"; + public const string ChecklistMirrored = "\xf0b5"; + public const string StatusCircle7 = "\xf0b6"; + public const string StatusCheckmark7 = "\xf0b7"; + public const string StatusErrorCircle7 = "\xf0b8"; + public const string Connected = "\xf0b9"; + public const string PencilFill = "\xf0c6"; + public const string CalligraphyFill = "\xf0c7"; + public const string QuarterStarLeft = "\xf0ca"; + public const string QuarterStarRight = "\xf0cb"; + public const string ThreeQuarterStarLeft = "\xf0cc"; + public const string ThreeQuarterStarRight = "\xf0cd"; + public const string QuietHoursBadge12 = "\xf0ce"; + public const string BackMirrored = "\xf0d2"; + public const string ForwardMirrored = "\xf0d3"; + public const string ChromeBackContrast = "\xf0d5"; + public const string ChromeBackContrastMirrored = "\xf0d6"; + public const string ChromeBackToWindowContrast = "\xf0d7"; + public const string ChromeFullScreenContrast = "\xf0d8"; + public const string GridView = "\xf0e2"; + public const string ClipboardList = "\xf0e3"; + public const string ClipboardListMirrored = "\xf0e4"; + public const string OutlineQuarterStarLeft = "\xf0e5"; + public const string OutlineQuarterStarRight = "\xf0e6"; + public const string OutlineHalfStarLeft = "\xf0e7"; + public const string OutlineHalfStarRight = "\xf0e8"; + public const string OutlineThreeQuarterStarLeft = "\xf0e9"; + public const string OutlineThreeQuarterStarRight = "\xf0ea"; + public const string SpatialVolume0 = "\xf0eb"; + public const string SpatialVolume1 = "\xf0ec"; + public const string SpatialVolume2 = "\xf0ed"; + public const string SpatialVolume3 = "\xf0ee"; + public const string ApplicationGuard = "\xf0ef"; + public const string OutlineStarLeftHalf = "\xf0f7"; + public const string OutlineStarRightHalf = "\xf0f8"; + public const string ChromeAnnotateContrast = "\xf0f9"; + public const string DefenderBadge12 = "\xf0fb"; + public const string DetachablePC = "\xf103"; + public const string LeftStick = "\xf108"; + public const string RightStick = "\xf109"; + public const string TriggerLeft = "\xf10a"; + public const string TriggerRight = "\xf10b"; + public const string BumperLeft = "\xf10c"; + public const string BumperRight = "\xf10d"; + public const string Dpad = "\xf10e"; + public const string EnglishPunctuation = "\xf110"; + public const string ChinesePunctuation = "\xf111"; + public const string HMD = "\xf119"; + public const string CtrlSpatialRight = "\xf11b"; + public const string PaginationDotOutline10 = "\xf126"; + public const string PaginationDotSolid10 = "\xf127"; + public const string StrokeErase2 = "\xf128"; + public const string SmallErase = "\xf129"; + public const string LargeErase = "\xf12a"; + public const string FolderHorizontal = "\xf12b"; + public const string MicrophoneListening = "\xf12e"; + public const string StatusExclamationCircle7 = "\xf12f"; + public const string Video360 = "\xf131"; + public const string GiftboxOpen = "\xf133"; + public const string StatusCircleOuter = "\xf136"; + public const string StatusCircleInner = "\xf137"; + public const string StatusCircleRing = "\xf138"; + public const string StatusTriangleOuter = "\xf139"; + public const string StatusTriangleInner = "\xf13a"; + public const string StatusTriangleExclamation = "\xf13b"; + public const string StatusCircleExclamation = "\xf13c"; + public const string StatusCircleErrorX = "\xf13d"; + public const string StatusCircleCheckmark = "\xf13e"; + public const string StatusCircleInfo = "\xf13f"; + public const string StatusCircleBlock = "\xf140"; + public const string StatusCircleBlock2 = "\xf141"; + public const string StatusCircleQuestionMark = "\xf142"; + public const string StatusCircleSync = "\xf143"; + public const string Dial1 = "\xf146"; + public const string Dial2 = "\xf147"; + public const string Dial3 = "\xf148"; + public const string Dial4 = "\xf149"; + public const string Dial5 = "\xf14a"; + public const string Dial6 = "\xf14b"; + public const string Dial7 = "\xf14c"; + public const string Dial8 = "\xf14d"; + public const string Dial9 = "\xf14e"; + public const string Dial10 = "\xf14f"; + public const string Dial11 = "\xf150"; + public const string Dial12 = "\xf151"; + public const string Dial13 = "\xf152"; + public const string Dial14 = "\xf153"; + public const string Dial15 = "\xf154"; + public const string Dial16 = "\xf155"; + public const string DialShape1 = "\xf156"; + public const string DialShape2 = "\xf157"; + public const string DialShape3 = "\xf158"; + public const string DialShape4 = "\xf159"; + public const string ClosedCaptionsInternational = "\xf15f"; + public const string TollSolid = "\xf161"; + public const string TrafficCongestionSolid = "\xf163"; + public const string ExploreContentSingle = "\xf164"; + public const string CollapseContent = "\xf165"; + public const string CollapseContentSingle = "\xf166"; + public const string InfoSolid = "\xf167"; + public const string GroupList = "\xf168"; + public const string CaretBottomRightSolidCenter8 = "\xf169"; + public const string ProgressRingDots = "\xf16a"; + public const string Checkbox14 = "\xf16b"; + public const string CheckboxComposite14 = "\xf16c"; + public const string CheckboxIndeterminateCombo14 = "\xf16d"; + public const string CheckboxIndeterminateCombo = "\xf16e"; + public const string StatusPause7 = "\xf175"; + public const string CharacterAppearance = "\xf17f"; + public const string Lexicon = "\xf180"; + public const string ScreenTime = "\xf182"; + public const string HeadlessDevice = "\xf191"; + public const string NetworkSharing = "\xf193"; + public const string EyeGaze = "\xf19d"; + public const string ToggleLeft = "\xf19e"; + public const string ToggleRight = "\xf19f"; + public const string WindowsInsider = "\xf1ad"; + public const string ChromeSwitch = "\xf1cb"; + public const string ChromeSwitchContast = "\xf1cc"; + public const string StatusCheckmark = "\xf1d8"; + public const string StatusCheckmarkLeft = "\xf1d9"; + public const string KeyboardLeftAligned = "\xf20c"; + public const string KeyboardRightAligned = "\xf20d"; + public const string KeyboardSettings = "\xf210"; + public const string NetworkPhysical = "\xf211"; + public const string IOT = "\xf22c"; + public const string UnknownMirrored = "\xf22e"; + public const string ViewDashboard = "\xf246"; + public const string ExploitProtectionSettings = "\xf259"; + public const string KeyboardNarrow = "\xf260"; + public const string Keyboard12Key = "\xf261"; + public const string KeyboardDock = "\xf26b"; + public const string KeyboardUndock = "\xf26c"; + public const string KeyboardLeftDock = "\xf26d"; + public const string KeyboardRightDock = "\xf26e"; + public const string Ear = "\xf270"; + public const string PointerHand = "\xf271"; + public const string Bullseye = "\xf272"; + public const string DocumentApproval = "\xf28b"; + public const string LocaleLanguage = "\xf2b7"; + public const string PassiveAuthentication = "\xf32a"; + public const string ColorSolid = "\xf354"; + public const string NetworkOffline = "\xf384"; + public const string NetworkConnected = "\xf385"; + public const string NetworkConnectedCheckmark = "\xf386"; + public const string SignOut = "\xf3b1"; + public const string StatusInfo = "\xf3cc"; + public const string StatusInfoLeft = "\xf3cd"; + public const string NearbySharing = "\xf3e2"; + public const string CtrlSpatialLeft = "\xf3e7"; + public const string InteractiveDashboard = "\xf404"; + public const string DeclineCall = "\xf405"; + public const string ClippingTool = "\xf406"; + public const string RectangularClipping = "\xf407"; + public const string FreeFormClipping = "\xf408"; + public const string CopyTo = "\xf413"; + public const string IDBadge = "\xf427"; + public const string DynamicLock = "\xf439"; + public const string PenTips = "\xf45e"; + public const string PenTipsMirrored = "\xf45f"; + public const string HWPJoin = "\xf460"; + public const string HWPInsert = "\xf461"; + public const string HWPStrikeThrough = "\xf462"; + public const string HWPScratchOut = "\xf463"; + public const string HWPSplit = "\xf464"; + public const string HWPNewLine = "\xf465"; + public const string HWPOverwrite = "\xf466"; + public const string MobWifiWarning1 = "\xf473"; + public const string MobWifiWarning2 = "\xf474"; + public const string MobWifiWarning3 = "\xf475"; + public const string MobWifiWarning4 = "\xf476"; + public const string MicLocationCombo = "\xf47f"; + public const string Globe2 = "\xf49a"; + public const string SpecialEffectSize = "\xf4a5"; + public const string GIF = "\xf4a9"; + public const string Sticker2 = "\xf4aa"; + public const string SurfaceHubSelected = "\xf4be"; + public const string HoloLensSelected = "\xf4bf"; + public const string Earbud = "\xf4c0"; + public const string MixVolumes = "\xf4c3"; + public const string Safe = "\xf540"; + public const string LaptopSecure = "\xf552"; + public const string PrintDefault = "\xf56d"; + public const string PageMirrored = "\xf56e"; + public const string LandscapeOrientationMirrored = "\xf56f"; + public const string ColorOff = "\xf570"; + public const string PrintAllPages = "\xf571"; + public const string PrintCustomRange = "\xf572"; + public const string PageMarginPortraitNarrow = "\xf573"; + public const string PageMarginPortraitNormal = "\xf574"; + public const string PageMarginPortraitModerate = "\xf575"; + public const string PageMarginPortraitWide = "\xf576"; + public const string PageMarginLandscapeNarrow = "\xf577"; + public const string PageMarginLandscapeNormal = "\xf578"; + public const string PageMarginLandscapeModerate = "\xf579"; + public const string PageMarginLandscapeWide = "\xf57a"; + public const string CollateLandscape = "\xf57b"; + public const string CollatePortrait = "\xf57c"; + public const string CollatePortraitSeparated = "\xf57d"; + public const string DuplexLandscapeOneSided = "\xf57e"; + public const string DuplexLandscapeOneSidedMirrored = "\xf57f"; + public const string DuplexLandscapeTwoSidedLongEdge = "\xf580"; + public const string DuplexLandscapeTwoSidedLongEdgeMirrored = "\xf581"; + public const string DuplexLandscapeTwoSidedShortEdge = "\xf582"; + public const string DuplexLandscapeTwoSidedShortEdgeMirrored = "\xf583"; + public const string DuplexPortraitOneSided = "\xf584"; + public const string DuplexPortraitOneSidedMirrored = "\xf585"; + public const string DuplexPortraitTwoSidedLongEdge = "\xf586"; + public const string DuplexPortraitTwoSidedLongEdgeMirrored = "\xf587"; + public const string DuplexPortraitTwoSidedShortEdge = "\xf588"; + public const string DuplexPortraitTwoSidedShortEdgeMirrored = "\xf589"; + public const string PPSOneLandscape = "\xf58a"; + public const string PPSTwoLandscape = "\xf58b"; + public const string PPSTwoPortrait = "\xf58c"; + public const string PPSFourLandscape = "\xf58d"; + public const string PPSFourPortrait = "\xf58e"; + public const string HolePunchOff = "\xf58f"; + public const string HolePunchPortraitLeft = "\xf590"; + public const string HolePunchPortraitRight = "\xf591"; + public const string HolePunchPortraitTop = "\xf592"; + public const string HolePunchPortraitBottom = "\xf593"; + public const string HolePunchLandscapeLeft = "\xf594"; + public const string HolePunchLandscapeRight = "\xf595"; + public const string HolePunchLandscapeTop = "\xf596"; + public const string HolePunchLandscapeBottom = "\xf597"; + public const string StaplingOff = "\xf598"; + public const string StaplingPortraitTopLeft = "\xf599"; + public const string StaplingPortraitTopRight = "\xf59a"; + public const string StaplingPortraitBottomRight = "\xf59b"; + public const string StaplingPortraitTwoLeft = "\xf59c"; + public const string StaplingPortraitTwoRight = "\xf59d"; + public const string StaplingPortraitTwoTop = "\xf59e"; + public const string StaplingPortraitTwoBottom = "\xf59f"; + public const string StaplingPortraitBookBinding = "\xf5a0"; + public const string StaplingLandscapeTopLeft = "\xf5a1"; + public const string StaplingLandscapeTopRight = "\xf5a2"; + public const string StaplingLandscapeBottomLeft = "\xf5a3"; + public const string StaplingLandscapeBottomRight = "\xf5a4"; + public const string StaplingLandscapeTwoLeft = "\xf5a5"; + public const string StaplingLandscapeTwoRight = "\xf5a6"; + public const string StaplingLandscapeTwoTop = "\xf5a7"; + public const string StaplingLandscapeTwoBottom = "\xf5a8"; + public const string StaplingLandscapeBookBinding = "\xf5a9"; + public const string StatusDataTransferRoaming = "\xf5aa"; + public const string MobSIMError = "\xf5ab"; + public const string CollateLandscapeSeparated = "\xf5ac"; + public const string PPSOnePortrait = "\xf5ad"; + public const string StaplingPortraitBottomLeft = "\xf5ae"; + public const string PlaySolid = "\xf5b0"; + public const string RepeatOff = "\xf5e7"; + public const string Set = "\xf5ed"; + public const string SetSolid = "\xf5ee"; + public const string FuzzyReading = "\xf5ef"; + public const string VerticalBattery0 = "\xf5f2"; + public const string VerticalBattery1 = "\xf5f3"; + public const string VerticalBattery2 = "\xf5f4"; + public const string VerticalBattery3 = "\xf5f5"; + public const string VerticalBattery4 = "\xf5f6"; + public const string VerticalBattery5 = "\xf5f7"; + public const string VerticalBattery6 = "\xf5f8"; + public const string VerticalBattery7 = "\xf5f9"; + public const string VerticalBattery8 = "\xf5fa"; + public const string VerticalBattery9 = "\xf5fb"; + public const string VerticalBattery10 = "\xf5fc"; + public const string VerticalBatteryCharging0 = "\xf5fd"; + public const string VerticalBatteryCharging1 = "\xf5fe"; + public const string VerticalBatteryCharging2 = "\xf5ff"; + public const string VerticalBatteryCharging3 = "\xf600"; + public const string VerticalBatteryCharging4 = "\xf601"; + public const string VerticalBatteryCharging5 = "\xf602"; + public const string VerticalBatteryCharging6 = "\xf603"; + public const string VerticalBatteryCharging7 = "\xf604"; + public const string VerticalBatteryCharging8 = "\xf605"; + public const string VerticalBatteryCharging9 = "\xf606"; + public const string VerticalBatteryCharging10 = "\xf607"; + public const string VerticalBatteryUnknown = "\xf608"; + public const string SIMError = "\xf618"; + public const string SIMMissing = "\xf619"; + public const string SIMLock = "\xf61a"; + public const string ESIM = "\xf61b"; + public const string ESIMNoProfile = "\xf61c"; + public const string ESIMLocked = "\xf61d"; + public const string ESIMBusy = "\xf61e"; + public const string NoiseCancelation = "\xf61f"; + public const string NoiseCancelationOff = "\xf620"; + public const string MusicSharing = "\xf623"; + public const string MusicSharingOff = "\xf624"; + public const string CircleShapeSolid = "\xf63c"; + public const string WifiCallBars = "\xf657"; + public const string WifiCall0 = "\xf658"; + public const string WifiCall1 = "\xf659"; + public const string WifiCall2 = "\xf65a"; + public const string WifiCall3 = "\xf65b"; + public const string WifiCall4 = "\xf65c"; + public const string CHTLanguageBar = "\xf69e"; + public const string ComposeMode = "\xf6a9"; + public const string ExpressiveInputEntry = "\xf6b8"; + public const string EmojiTabMoreSymbols = "\xf6ba"; + public const string WebSearch = "\xf6fa"; + public const string Kiosk = "\xf712"; + public const string RTTLogo = "\xf714"; + public const string VoiceCall = "\xf715"; + public const string GoToMessage = "\xf716"; + public const string ReturnToCall = "\xf71a"; + public const string StartPresenting = "\xf71c"; + public const string StopPresenting = "\xf71d"; + public const string ProductivityMode = "\xf71e"; + public const string SetHistoryStatus = "\xf738"; + public const string SetHistoryStatus2 = "\xf739"; + public const string Keyboardsettings20 = "\xf73d"; + public const string OneHandedRight20 = "\xf73e"; + public const string OneHandedLeft20 = "\xf73f"; + public const string Split20 = "\xf740"; + public const string Full20 = "\xf741"; + public const string Handwriting20 = "\xf742"; + public const string ChevronLeft20 = "\xf743"; + public const string ChevronLeft32 = "\xf744"; + public const string ChevronRight20 = "\xf745"; + public const string ChevronRight32 = "\xf746"; + public const string Event12 = "\xf763"; + public const string MicOff2 = "\xf781"; + public const string DeliveryOptimization = "\xf785"; + public const string CancelMedium = "\xf78a"; + public const string SearchMedium = "\xf78b"; + public const string AcceptMedium = "\xf78c"; + public const string RevealPasswordMedium = "\xf78d"; + public const string DeleteWord = "\xf7ad"; + public const string DeleteWordFill = "\xf7ae"; + public const string DeleteLines = "\xf7af"; + public const string DeleteLinesFill = "\xf7b0"; + public const string InstertWords = "\xf7b1"; + public const string InstertWordsFill = "\xf7b2"; + public const string JoinWords = "\xf7b3"; + public const string JoinWordsFill = "\xf7b4"; + public const string OverwriteWords = "\xf7b5"; + public const string OverwriteWordsFill = "\xf7b6"; + public const string AddNewLine = "\xf7b7"; + public const string AddNewLineFill = "\xf7b8"; + public const string OverwriteWordsKorean = "\xf7b9"; + public const string OverwriteWordsFillKorean = "\xf7ba"; + public const string EducationIcon = "\xf7bb"; + public const string WindowSnipping = "\xf7ed"; + public const string VideoCapture = "\xf7ee"; + public const string StatusSecured = "\xf809"; + public const string NarratorApp = "\xf83b"; + public const string PowerButtonUpdate = "\xf83d"; + public const string RestartUpdate = "\xf83e"; + public const string UpdateStatusDot = "\xf83f"; + public const string Eject = "\xf847"; + public const string Spelling = "\xf87b"; + public const string SpellingKorean = "\xf87c"; + public const string SpellingSerbian = "\xf87d"; + public const string SpellingChinese = "\xf87e"; + public const string FolderSelect = "\xf89a"; + public const string SmartScreen = "\xf8a5"; + public const string ExploitProtection = "\xf8a6"; + public const string AddBold = "\xf8aa"; + public const string SubtractBold = "\xf8ab"; + public const string BackSolidBold = "\xf8ac"; + public const string ForwardSolidBold = "\xf8ad"; + public const string PauseBold = "\xf8ae"; + public const string ClickSolid = "\xf8af"; + public const string SettingsSolid = "\xf8b0"; + public const string MicrophoneSolidBold = "\xf8b1"; + public const string SpeechSolidBold = "\xf8b2"; + public const string ClickedOutLoudSolidBold = "\xf8b3"; +} diff --git a/QuickLook.Common/ExtensionMethods/BitmapExtensions.cs b/QuickLook.Common/ExtensionMethods/BitmapExtensions.cs new file mode 100644 index 0000000..d874be8 --- /dev/null +++ b/QuickLook.Common/ExtensionMethods/BitmapExtensions.cs @@ -0,0 +1,143 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Threading.Tasks; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using PixelFormat = System.Windows.Media.PixelFormat; + +namespace QuickLook.Common.ExtensionMethods; + +public static class BitmapExtensions +{ + public static BitmapSource ToBitmapSource(this Bitmap source) + { + var orgSource = source; + BitmapSource bs = null; + try + { + var data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), + ImageLockMode.ReadOnly, source.PixelFormat); + + // BitmapSource.Create throws an exception when the image is scanned backward. + // The Clone() will make it back scanning forward. + if (data.Stride < 0) + { + source.UnlockBits(data); + source = (Bitmap)source.Clone(); + data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), + ImageLockMode.ReadOnly, source.PixelFormat); + } + + bs = BitmapSource.Create(source.Width, source.Height, Math.Floor(source.HorizontalResolution), + Math.Floor(source.VerticalResolution), ConvertPixelFormat(source.PixelFormat), null, + data.Scan0, data.Stride * source.Height, data.Stride); + + source.UnlockBits(data); + + bs.Freeze(); + } + catch + { + // ignored + } + finally + { + if (orgSource != source) + source.Dispose(); + } + + return bs; + } + + public static Bitmap ToBitmap(this BitmapSource source) + { + using var outStream = new MemoryStream(); + BitmapEncoder enc = new BmpBitmapEncoder(); + enc.Frames.Add(BitmapFrame.Create(source)); + enc.Save(outStream); + using var bitmap = new Bitmap(outStream); + + return new Bitmap(bitmap); + } + + private static PixelFormat ConvertPixelFormat( + System.Drawing.Imaging.PixelFormat sourceFormat) + { + return sourceFormat switch + { + System.Drawing.Imaging.PixelFormat.Format24bppRgb => PixelFormats.Bgr24, + System.Drawing.Imaging.PixelFormat.Format32bppArgb => PixelFormats.Bgra32, + System.Drawing.Imaging.PixelFormat.Format32bppRgb => PixelFormats.Bgr32, + _ => new PixelFormat(), + }; + } + + public static bool IsDarkImage(this Bitmap image) + { + // convert to 24-bit RGB image + image = image.Clone(new Rectangle(0, 0, image.Width, image.Height), + System.Drawing.Imaging.PixelFormat.Format24bppRgb); + + var sampleCount = (int)(0.2 * 400 * 400); + const int pixelSize = 24 / 8; + var data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), + ImageLockMode.ReadWrite, image.PixelFormat); + + var darks = 0; + unsafe + { + var pFirst = (byte*)data.Scan0; + + Parallel.For(0, sampleCount, n => + { + var rand = new Random(n); + var row = rand.Next(0, data.Height); + var col = rand.Next(0, data.Width); + var pos = pFirst + row * data.Stride + col * pixelSize; + + var b = pos[0]; + var g = pos[1]; + var r = pos[2]; + + var y = (0.299 * r + 0.587 * g + 0.114 * b) / 255; + + if (y < 0.5) + darks++; + }); + } + + image.UnlockBits(data); + image.Dispose(); + + return darks > 0.65 * sampleCount; + } + + public static BitmapImage LoadBitmapImage(this Uri source) + { + var bitmap = new BitmapImage(); + bitmap.BeginInit(); + bitmap.CacheOption = BitmapCacheOption.OnLoad; + bitmap.UriSource = source; + bitmap.EndInit(); + return bitmap; + } +} diff --git a/QuickLook.Common/ExtensionMethods/DispatcherExtensions.cs b/QuickLook.Common/ExtensionMethods/DispatcherExtensions.cs new file mode 100644 index 0000000..80581af --- /dev/null +++ b/QuickLook.Common/ExtensionMethods/DispatcherExtensions.cs @@ -0,0 +1,46 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Threading.Tasks; +using System.Windows.Threading; + +namespace QuickLook.Common.ExtensionMethods; + +public static class DispatcherExtensions +{ + public static void Delay(this Dispatcher disp, int delayMs, + Action action, object parm = null) + { + _ = Task.Delay(delayMs).ContinueWith(t => { _ = disp.Invoke(action, parm); }); + } + + public static void DelayWithPriority(this Dispatcher disp, int delayMs, + Action action, object parm = null, + DispatcherPriority priority = DispatcherPriority.ApplicationIdle) + { + _ = Task.Delay(delayMs).ContinueWith(t => { _ = disp.BeginInvoke(action, priority, parm); }); + } + + public static async Task DelayAsync(this Dispatcher disp, int delayMs, + Action action, object parm = null, + DispatcherPriority priority = DispatcherPriority.ApplicationIdle) + { + await Task.Delay(delayMs); + await disp.BeginInvoke(action, priority, parm); + } +} diff --git a/QuickLook.Common/ExtensionMethods/EnumerableExtensions.cs b/QuickLook.Common/ExtensionMethods/EnumerableExtensions.cs new file mode 100644 index 0000000..784e83a --- /dev/null +++ b/QuickLook.Common/ExtensionMethods/EnumerableExtensions.cs @@ -0,0 +1,30 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Collections.Generic; + +namespace QuickLook.Common.ExtensionMethods; + +public static class EnumerableExtensions +{ + public static void ForEach(this IEnumerable enumeration, Action action) + { + foreach (var item in enumeration) + action(item); + } +} diff --git a/QuickLook.Common/ExtensionMethods/FileExtensions.cs b/QuickLook.Common/ExtensionMethods/FileExtensions.cs new file mode 100644 index 0000000..f6eb037 --- /dev/null +++ b/QuickLook.Common/ExtensionMethods/FileExtensions.cs @@ -0,0 +1,47 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; + +namespace QuickLook.Common.ExtensionMethods; + +public static class FileExtensions +{ + public static string ToPrettySize(this long value, int decimalPlaces = 0) + { + const long OneKb = 1024L; + const long OneMb = OneKb * 1024L; + const long OneGb = OneMb * 1024L; + const long OneTb = OneGb * 1024L; + + var asTb = Math.Round((double)value / OneTb, decimalPlaces); + var asGb = Math.Round((double)value / OneGb, decimalPlaces); + var asMb = Math.Round((double)value / OneMb, decimalPlaces); + var asKb = Math.Round((double)value / OneKb, decimalPlaces); + var chosenValue = asTb > 1 + ? $"{asTb} TB" + : asGb > 1 + ? $"{asGb} GB" + : asMb > 1 + ? $"{asMb} MB" + : asKb > 1 + ? $"{asKb} KB" + : $"{Math.Round((double)value, decimalPlaces)} bytes"; + + return chosenValue; + } +} diff --git a/QuickLook.Common/ExtensionMethods/TypeExtensions.cs b/QuickLook.Common/ExtensionMethods/TypeExtensions.cs new file mode 100644 index 0000000..4e0a806 --- /dev/null +++ b/QuickLook.Common/ExtensionMethods/TypeExtensions.cs @@ -0,0 +1,28 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; + +namespace QuickLook.Common.ExtensionMethods; + +public static class TypeExtensions +{ + public static T CreateInstance(this Type t, params object[] paramArray) + { + return (T)Activator.CreateInstance(t, paramArray); + } +} diff --git a/QuickLook.Common/Helpers/DisplayDeviceHelper.cs b/QuickLook.Common/Helpers/DisplayDeviceHelper.cs new file mode 100644 index 0000000..08b61b3 --- /dev/null +++ b/QuickLook.Common/Helpers/DisplayDeviceHelper.cs @@ -0,0 +1,142 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows; +using System.Windows.Interop; +using static QuickLook.Common.NativeMethods.MsCms; +using static QuickLook.Common.NativeMethods.User32; + +namespace QuickLook.Common.Helpers; + +public static class DisplayDeviceHelper +{ + public const int DefaultDpi = 96; + + public static ScaleFactor GetScaleFactorFromWindow(Window window) + { + return GetScaleFactorFromWindow(new WindowInteropHelper(window).EnsureHandle()); + } + + public static ScaleFactor GetCurrentScaleFactor() + { + return GetScaleFactorFromWindow(GetForegroundWindow()); + } + + public static ScaleFactor GetScaleFactorFromWindow(nint hwnd) + { + var dpiX = DefaultDpi; + var dpiY = DefaultDpi; + + try + { + if (Environment.OSVersion.Version > new Version(6, 2)) // Windows 8.1 = 6.3.9200 + { + var hMonitor = MonitorFromWindow(hwnd, MonitorDefaults.TOPRIMARY); + GetDpiForMonitor(hMonitor, MonitorDpiType.EFFECTIVE_DPI, out dpiX, out dpiY); + } + else + { + using var g = Graphics.FromHwnd(IntPtr.Zero); + var desktop = g.GetHdc(); + try + { + dpiX = GetDeviceCaps(desktop, DeviceCap.LOGPIXELSX); + dpiY = GetDeviceCaps(desktop, DeviceCap.LOGPIXELSY); + } + finally + { + g.ReleaseHdc(desktop); + } + } + } + catch (Exception e) + { + ProcessHelper.WriteLog(e.ToString()); + } + + return new ScaleFactor { Horizontal = (float)dpiX / DefaultDpi, Vertical = (float)dpiY / DefaultDpi }; + } + + public static string GetMonitorColorProfileFromWindow(Window window) + { + try + { + var hMonitor = MonitorFromWindow(new WindowInteropHelper(window).EnsureHandle(), MonitorDefaults.TONEAREST); + return GetMonitorColorProfile(hMonitor); + } + catch (COMException ex) when (ex.HResult == unchecked((int)0x80263001)) + { + // Desktop composition is disabled (e.g., during eGPU reconnection) + ProcessHelper.WriteLog("Failed to get color profile: Desktop composition is disabled. This is expected during display reconfiguration."); + return null; + } + catch (Exception ex) + { + ProcessHelper.WriteLog($"Failed to get monitor color profile: {ex}"); + return null; + } + } + + public static string GetMonitorColorProfile(nint hMonitor) + { + var profileDir = new StringBuilder(255); + var pDirSize = (uint)profileDir.Capacity; + GetColorDirectory(null, profileDir, ref pDirSize); + + var mInfo = new MONITORINFOEX(); + mInfo.cbSize = (uint)Marshal.SizeOf(mInfo); + if (!GetMonitorInfo(hMonitor, ref mInfo)) + return null; + + var dd = new DISPLAYDEVICE(); + dd.cb = (uint)Marshal.SizeOf(dd); + if (!EnumDisplayDevices(mInfo.szDevice, 0, ref dd, 0)) + return null; + + WcsGetUsePerUserProfiles(dd.DeviceKey, CLASS_MONITOR, out bool usePerUserProfiles); + var scope = usePerUserProfiles ? WcsProfileManagementScope.CURRENT_USER : WcsProfileManagementScope.SYSTEM_WIDE; + + if (!WcsGetDefaultColorProfileSize(scope, dd.DeviceKey, ColorProfileType.ICC, ColorProfileSubtype.NONE, 0, out uint size)) + return null; + + var profileName = new StringBuilder((int)size); + if (!WcsGetDefaultColorProfile(scope, dd.DeviceKey, ColorProfileType.ICC, ColorProfileSubtype.NONE, 0, size, profileName)) + return null; + return System.IO.Path.Combine(profileDir.ToString(), profileName.ToString()); + } + + [DllImport("shcore.dll")] + private static extern uint + GetDpiForMonitor(nint hMonitor, MonitorDpiType dpiType, out int dpiX, out int dpiY); + + private enum MonitorDpiType + { + EFFECTIVE_DPI = 0, + ANGULAR_DPI = 1, + RAW_DPI = 2, + } + + public struct ScaleFactor + { + public float Horizontal; + public float Vertical; + } +} diff --git a/QuickLook.Common/Helpers/FileHelper.cs b/QuickLook.Common/Helpers/FileHelper.cs new file mode 100644 index 0000000..39b310b --- /dev/null +++ b/QuickLook.Common/Helpers/FileHelper.cs @@ -0,0 +1,159 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using Microsoft.Win32.SafeHandles; +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace QuickLook.Common.Helpers; + +public static class FileHelper +{ + public static bool IsExecutable(string path, out string appFriendlyName) + { + appFriendlyName = string.Empty; + var ext = Path.GetExtension(path).ToLower(); + var isExe = new[] { ".cmd", ".bat", ".pif", ".scf", ".exe", ".com", ".scr" }.Contains(ext.ToLower()); + + if (!isExe) + return false; + + appFriendlyName = FileVersionInfo.GetVersionInfo(path).FileDescription; + if (string.IsNullOrEmpty(appFriendlyName)) + appFriendlyName = Path.GetFileName(path); + + return true; + } + + public static string CreateTempFile(string folder, string filename = null) + { + if (string.IsNullOrWhiteSpace(filename)) + filename = Guid.NewGuid() + ".tmp"; + var fullPath = Path.Combine(folder, filename); + + var handle = new SafeFileHandle(IntPtr.Zero, true); + + try + { + Directory.CreateDirectory(folder); + + handle = NativeMethods.Kernel32.CreateFile(fullPath, FileAccess.ReadWrite, + FileShare.None, + IntPtr.Zero, FileMode.Create, FileAttributes.Temporary, IntPtr.Zero); + + if (handle.IsInvalid) + throw new UnauthorizedAccessException($"{folder} is not writable."); + + return fullPath; + } + finally + { + if (!handle.IsInvalid && !handle.IsClosed) + handle.Close(); + } + } + + public static bool GetAssocApplication(string path, out string appFriendlyName) + { + appFriendlyName = string.Empty; + var ext = Path.GetExtension(path).ToLower(); + + // no assoc. app. found + if (string.IsNullOrEmpty(GetAssocApplicationNative(ext, AssocStr.Command))) + if (string.IsNullOrEmpty(GetAssocApplicationNative(ext, AssocStr.AppId))) // UWP + return false; + + appFriendlyName = GetAssocApplicationNative(ext, AssocStr.FriendlyAppName); + if (string.IsNullOrEmpty(appFriendlyName)) + appFriendlyName = Path.GetFileName(path); + + return true; + } + + [DllImport("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra, + [Out] StringBuilder sOut, [In][Out] ref uint nOut); + + private static string GetAssocApplicationNative(string fileExtensionIncludingDot, AssocStr str) + { + uint cOut = 0; + if (AssocQueryString(AssocF.Verify | AssocF.RemapRunDll | AssocF.InitIgnoreUnknown, str, + fileExtensionIncludingDot, null, null, + ref cOut) != 1) + return null; + + var pOut = new StringBuilder((int)cOut); + if (AssocQueryString(AssocF.Verify | AssocF.RemapRunDll | AssocF.InitIgnoreUnknown, str, + fileExtensionIncludingDot, null, pOut, + ref cOut) != 0) + return null; + + return pOut.ToString(); + } + + [Flags] + private enum AssocF + { + InitNoRemapCLSID = 0x1, + InitByExeName = 0x2, + OpenByExeName = 0x2, + InitDefaultToStar = 0x4, + InitDefaultToFolder = 0x8, + NoUserSettings = 0x10, + NoTruncate = 0x20, + Verify = 0x40, + RemapRunDll = 0x80, + NoFixUps = 0x100, + IgnoreBaseClass = 0x200, + InitIgnoreUnknown = 0x400, + InitFixedProgid = 0x800, + IsProtocol = 0x1000, + InitForFile = 0x2000, + } + + private enum AssocStr + { + Command = 1, + Executable, + FriendlyDocName, + FriendlyAppName, + NoOpen, + ShellNewValue, + DdeCommand, + DdeIfExec, + DdeApplication, + DdeTopic, + InfoTip, + QuickTip, + TileInfo, + ContentType, + DefaultIcon, + ShellExtension, + DropTarget, + DelegateExecute, + SupportedUriProtocols, + ProgId, + AppId, + AppPublisher, + AppIconReference, + Max, + } +} diff --git a/QuickLook.Common/Helpers/OSThemeHelper.cs b/QuickLook.Common/Helpers/OSThemeHelper.cs new file mode 100644 index 0000000..5113c62 --- /dev/null +++ b/QuickLook.Common/Helpers/OSThemeHelper.cs @@ -0,0 +1,41 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using Microsoft.Win32; + +namespace QuickLook.Common.Helpers; + +public static class OSThemeHelper +{ + public static bool AppsUseDarkTheme() + { + var value = Registry.GetValue( + @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", + "AppsUseLightTheme", 1); + + return value != null && (int)value == 0; + } + + public static bool SystemUsesDarkTheme() + { + var value = Registry.GetValue( + @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", + "SystemUsesLightTheme", 0); + + return value == null || (int)value == 0; + } +} diff --git a/QuickLook.Common/Helpers/PluginHelper.cs b/QuickLook.Common/Helpers/PluginHelper.cs new file mode 100644 index 0000000..cc8da36 --- /dev/null +++ b/QuickLook.Common/Helpers/PluginHelper.cs @@ -0,0 +1,79 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Diagnostics; +using System.Linq; +using System.Reflection; + +namespace QuickLook.Common.Helpers; + +public static class PluginHelper +{ + public static void RunAndClosePreview() + { + GetInstance()?.RunAndClosePreview(); + } + + public static void InvokePreview(string path = null) + { + GetInstance()?.InvokePreview(path); + } + + public static void InvokePreviewWithOption(string path = null, string options = null) + { + GetInstance()?.InvokePreviewWithOption(path, options); + } + + public static void InvokePluginPreview(string plugin, string path = null) + { + GetInstance()?.InvokePluginPreview(plugin, path); + } + + private static dynamic GetInstance() + { + try + { + // Obtain the instance from QuickLook::ViewWindowManager.GetInstance() + Type type = AppDomain.CurrentDomain + .GetAssemblies() + .Select(a => a.GetType("QuickLook.ViewWindowManager", throwOnError: false)) + .FirstOrDefault(t => t != null); + + if (type == null) + { + return null; + } + + MethodInfo method = type.GetMethod("GetInstance", + BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + + if (method == null) + { + return null; + } + + return method.Invoke(null, null); + } + catch (Exception e) + { + Debug.WriteLine(e); + } + + return null; + } +} diff --git a/QuickLook.Common/Helpers/ProcessHelper.cs b/QuickLook.Common/Helpers/ProcessHelper.cs new file mode 100644 index 0000000..9e92b34 --- /dev/null +++ b/QuickLook.Common/Helpers/ProcessHelper.cs @@ -0,0 +1,89 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using QuickLook.Common.NativeMethods; +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Threading.Tasks; +using System.Windows; + +namespace QuickLook.Common.Helpers; + +public static class ProcessHelper +{ + private const int ErrorInsufficientBuffer = 0x7A; + + public static void PerformAggressiveGC() + { + // delay some time to make sure that all windows are closed + Task.Delay(2000).ContinueWith(t => GC.Collect(GC.MaxGeneration)); + } + + public static bool IsRunningAsUWP() + { + if (Environment.OSVersion.Version < new Version(6, 2)) // Windows 8 + return false; + + try + { + uint len = 0; + var r = Kernel32.GetCurrentPackageFullName(ref len, null); + + return r == ErrorInsufficientBuffer; + } + catch (EntryPointNotFoundException) + { + return false; + } + } + + public static bool IsOnWindows10S() + { + const uint PRODUCT_CLOUD = 0x000000B2; // Windows 10 S + const uint PRODUCT_CLOUDN = 0x000000B3; // Windows 10 S N + + Kernel32.GetProductInfo(Environment.OSVersion.Version.Major, + Environment.OSVersion.Version.Minor, 0, 0, out var osType); + + return osType == PRODUCT_CLOUD || osType == PRODUCT_CLOUDN; + } + + public static bool IsShuttingDown() + { + var isShuttingDownProperty = + typeof(Application).GetProperty("IsShuttingDown", BindingFlags.NonPublic | BindingFlags.Static); + if (isShuttingDownProperty == null) + throw new Exception("Unable to detect Application.IsShuttingDown."); + return (bool)isShuttingDownProperty.GetValue(Application.Current); + } + + public static void WriteLog(string msg) + { + Debug.WriteLine(msg); + + var logFilePath = Path.Combine(SettingHelper.LocalDataPath, @"QuickLook.Exception.log"); + + using var writer = new StreamWriter(new FileStream(logFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read)); + writer.BaseStream.Seek(0, SeekOrigin.End); + + writer.WriteLine($"========{DateTime.Now}========"); + writer.WriteLine(msg); + writer.WriteLine(); + } +} diff --git a/QuickLook.Common/Helpers/SettingHelper.cs b/QuickLook.Common/Helpers/SettingHelper.cs new file mode 100644 index 0000000..10c3e4d --- /dev/null +++ b/QuickLook.Common/Helpers/SettingHelper.cs @@ -0,0 +1,146 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Runtime.Serialization; +using System.Xml; + +namespace QuickLook.Common.Helpers; + +public static class SettingHelper +{ + public static readonly string LocalDataPath = + IsPortableVersion() + ? Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty, + @"UserData\") + : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + @"pooi.moe\QuickLook\"); + + private static readonly Dictionary FileCache = []; + + public static T Get(string id, T failsafe = default, string domain = "QuickLook") + { + if (!typeof(T).IsSerializable && !typeof(ISerializable).IsAssignableFrom(typeof(T))) + throw new InvalidOperationException("A serializable Type is required"); + + var file = Path.Combine(LocalDataPath, domain + ".config"); + + var doc = GetConfigFile(file); + + // try to get setting + var s = GetSettingFromXml(doc, id, failsafe); + + return s != null ? s : failsafe; + } + + public static void Set(string id, object value, string domain = "QuickLook") + { + if (!value.GetType().IsSerializable) + throw new NotSupportedException("New value if not serializable."); + + var file = Path.Combine(LocalDataPath, domain + ".config"); + + WriteSettingToXml(GetConfigFile(file), id, value); + } + + public static bool IsPortableVersion() + { + var lck = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty, + "portable.lock"); + + return File.Exists(lck); + } + + private static T GetSettingFromXml(XmlDocument doc, string id, T failsafe) + { + var v = doc.SelectSingleNode($@"/Settings/{id}"); + + try + { + var result = v == null ? failsafe : (T)Convert.ChangeType(v.InnerText, typeof(T)); + return result; + } + catch (Exception) + { + return failsafe; + } + } + + private static void WriteSettingToXml(XmlDocument doc, string id, object value) + { + var v = doc.SelectSingleNode($@"/Settings/{id}"); + + if (v != null) + { + v.InnerText = value.ToString(); + } + else + { + var node = doc.CreateNode(XmlNodeType.Element, id, doc.NamespaceURI); + node.InnerText = value.ToString(); + doc.SelectSingleNode(@"/Settings")?.AppendChild(node); + } + + doc.Save(new Uri(doc.BaseURI).LocalPath); + } + + private static XmlDocument GetConfigFile(string file) + { + if (FileCache.ContainsKey(file)) + return FileCache[file]; + + Directory.CreateDirectory(Path.GetDirectoryName(file)); + if (!File.Exists(file)) + CreateNewConfig(file); + + var doc = new XmlDocument(); + try + { + doc.Load(file); + } + catch (XmlException) + { + CreateNewConfig(file); + doc.Load(file); + } + + if (doc.SelectSingleNode(@"/Settings") == null) + { + CreateNewConfig(file); + doc.Load(file); + } + + FileCache.Add(file, doc); + return doc; + } + + private static void CreateNewConfig(string file) + { + using (var writer = XmlWriter.Create(file)) + { + writer.WriteStartDocument(); + writer.WriteStartElement("Settings"); + writer.WriteEndElement(); + writer.WriteEndDocument(); + + writer.Flush(); + } + } +} diff --git a/QuickLook.Common/Helpers/TranslationHelper.cs b/QuickLook.Common/Helpers/TranslationHelper.cs new file mode 100644 index 0000000..3507c3a --- /dev/null +++ b/QuickLook.Common/Helpers/TranslationHelper.cs @@ -0,0 +1,86 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Xml.XPath; + +namespace QuickLook.Common.Helpers; + +public static class TranslationHelper +{ + private static readonly CultureInfo CurrentCultureInfo = CultureInfo.CurrentUICulture; + + private static readonly Dictionary FileCache = []; + + public static string Get(string id, string file = null, CultureInfo locale = null, string failsafe = null, + string domain = "QuickLook") + { + if (file == null) + { + var subDir = domain == "QuickLook" ? string.Empty : $"QuickLook.Plugin\\{domain}"; + file = Path.Combine( + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), // path of QuickLook.Common.dll + subDir, "Translations.config"); + } + + if (!File.Exists(file)) + return failsafe ?? id; + + if (locale == null) + locale = CurrentCultureInfo; + + var nav = GetLangFile(file); + + // try to get string + var s = GetStringFromXml(nav, id, locale); + if (s != null) + return s; + + // try again for parent language + if (locale.Parent.Name != string.Empty) + s = GetStringFromXml(nav, id, locale.Parent); + if (s != null) + return s; + + // use fallback language + s = GetStringFromXml(nav, id, CultureInfo.GetCultureInfo("en")); + if (s != null) + return s; + + return failsafe ?? id; + } + + private static string GetStringFromXml(XPathNavigator nav, string id, CultureInfo locale) + { + var result = nav.SelectSingleNode($@"/Translations/{locale.Name}/{id}"); + + return result?.Value; + } + + private static XPathNavigator GetLangFile(string file) + { + if (FileCache.ContainsKey(file)) + return FileCache[file]; + + var res = new XPathDocument(file).CreateNavigator(); + FileCache.Add(file, res); + return res; + } +} diff --git a/QuickLook.Common/Helpers/WindowHelper.cs b/QuickLook.Common/Helpers/WindowHelper.cs new file mode 100644 index 0000000..981ab30 --- /dev/null +++ b/QuickLook.Common/Helpers/WindowHelper.cs @@ -0,0 +1,259 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using QuickLook.Common.NativeMethods; +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Forms; +using System.Windows.Interop; +using System.Windows.Media; + +namespace QuickLook.Common.Helpers; + +public static class WindowHelper +{ + public enum WindowCompositionAttribute + { + WcaAccentPolicy = 19, + } + + public static Size GetCurrentDesktopSize() + { + var scale = DisplayDeviceHelper.GetCurrentScaleFactor(); + var rect = GetCurrentDesktopRectInPixel(); + + return new Size(rect.Width / scale.Horizontal, rect.Height / scale.Vertical); + } + + public static Rect GetCurrentDesktopRectInPixel() + { + return GetDesktopRectFromWindowInPixel(User32.GetForegroundWindow()); + } + + public static Rect GetDesktopRectFromWindowInPixel(Window window) + { + return GetDesktopRectFromWindowInPixel(new WindowInteropHelper(window).Handle); + } + + public static Rect GetDesktopRectFromWindowInPixel(nint hwnd) + { + var screen = Screen.FromHandle(hwnd).WorkingArea; + + var area = new Rect(new Point(screen.X, screen.Y), + new Size(screen.Width, screen.Height)); + + return area; + } + + public static void BringToFront(this Window window, bool keep) + { + var handle = new WindowInteropHelper(window).Handle; + keep |= window.Topmost; + + User32.SetWindowPos(handle, User32.HWND_TOPMOST, 0, 0, 0, 0, + User32.SWP_NOMOVE | User32.SWP_NOSIZE | User32.SWP_NOACTIVATE); + + if (!keep) + User32.SetWindowPos(handle, User32.HWND_NOTOPMOST, 0, 0, 0, 0, + User32.SWP_NOMOVE | User32.SWP_NOSIZE | User32.SWP_NOACTIVATE); + } + + public static void MoveWindow(this Window window, + double pxLeft, + double pxTop, + double width, + double height) + { + var handle = new WindowInteropHelper(window).EnsureHandle(); + + // scale the size to the primary display + TransformToPixels(window, width, height, + out var pxWidth, out var pxHeight); + + // Use absolute location and relative size. WPF will scale the size to the target display + User32.MoveWindow(handle, (int)Math.Round(pxLeft), (int)Math.Round(pxTop), pxWidth, pxHeight, true); + } + + public static Rect GetWindowRectInPixel(this Window window) + { + var handle = new WindowInteropHelper(window).EnsureHandle(); + + User32.GetWindowRect(handle, out User32.RECT nRect); + + return new Rect(new Point(nRect.Left, nRect.Top), new Point(nRect.Right, nRect.Bottom)); + } + + private static void TransformToPixels(this Visual visual, + double unitX, + double unitY, + out int pixelX, + out int pixelY) + { + Matrix matrix; + var source = PresentationSource.FromVisual(visual); + if (source != null) + matrix = source.CompositionTarget.TransformToDevice; + else + using (var src = new HwndSource(new HwndSourceParameters())) + { + matrix = src.CompositionTarget.TransformToDevice; + } + + pixelX = (int)Math.Round(matrix.M11 * unitX); + pixelY = (int)Math.Round(matrix.M22 * unitY); + } + + public static bool IsForegroundWindowBelongToSelf() + { + var hwnd = User32.GetForegroundWindow(); + if (hwnd == IntPtr.Zero) + return false; + + User32.GetWindowThreadProcessId(hwnd, out var procId); + return procId == Process.GetCurrentProcess().Id; + } + + public static void SetNoactivate(this Window window) + { + var hwnd = new WindowInteropHelper(window).Handle; + User32.SetWindowLong(hwnd, User32.GWL_EXSTYLE, + User32.GetWindowLong(hwnd, User32.GWL_EXSTYLE) | + User32.WS_EX_NOACTIVATE); + } + + public static void RemoveWindowControls(this Window window) + { + var hwnd = new WindowInteropHelper(window).Handle; + User32.SetWindowLong(hwnd, User32.GWL_STYLE, + User32.GetWindowLong(hwnd, User32.GWL_STYLE) & + ~User32.WS_SYSMENU); + } + + public static void EnableBlur(Window window) + { + var accent = new AccentPolicy(); + var accentStructSize = Marshal.SizeOf(accent); + accent.AccentState = AccentState.AccentEnableBlurbehind; + accent.AccentFlags = 2; + accent.GradientColor = 0x99FFFFFF; + + var accentPtr = Marshal.AllocHGlobal(accentStructSize); + Marshal.StructureToPtr(accent, accentPtr, false); + + var data = new WindowCompositionAttributeData + { + Attribute = WindowCompositionAttribute.WcaAccentPolicy, + SizeOfData = accentStructSize, + Data = accentPtr + }; + + User32.SetWindowCompositionAttribute(new WindowInteropHelper(window).Handle, ref data); + + Marshal.FreeHGlobal(accentPtr); + } + + public static void DisableBlur(Window window) + { + var accent = new AccentPolicy(); + var accentStructSize = Marshal.SizeOf(accent); + accent.AccentState = AccentState.AccentDisabled; + + var accentPtr = Marshal.AllocHGlobal(accentStructSize); + Marshal.StructureToPtr(accent, accentPtr, false); + + var data = new WindowCompositionAttributeData + { + Attribute = WindowCompositionAttribute.WcaAccentPolicy, + SizeOfData = accentStructSize, + Data = accentPtr + }; + + var hwnd = new WindowInteropHelper(window).EnsureHandle(); + User32.SetWindowCompositionAttribute(hwnd, ref data); + + Marshal.FreeHGlobal(accentPtr); + + var margins = new Dwmapi.Margins(0, 0, 0, 0); + Dwmapi.DwmExtendFrameIntoClientArea(hwnd, ref margins); + + if (Environment.OSVersion.Version >= new Version(10, 0, 22523)) + { + var backdropType = (int)Dwmapi.SystembackdropType.None; + Dwmapi.DwmSetWindowAttribute(hwnd, (uint)Dwmapi.WindowAttribute.SystembackdropType, ref backdropType, Marshal.SizeOf(typeof(int))); + } + else if (Environment.OSVersion.Version >= new Version(10, 0, 21996)) + { + var micaEnabled = 0; + Dwmapi.DwmSetWindowAttribute(hwnd, (uint)Dwmapi.WindowAttribute.MicaEffect, ref micaEnabled, Marshal.SizeOf(typeof(int))); + } + } + + private static void EnableDwmBlur(Window window, bool isDarkTheme, uint dwAttribute, int pvAttribute) + { + // Mica will handle the color + window.Background = Brushes.Transparent; + + var hwnd = new WindowInteropHelper(window).Handle; + + var isDarkThemeInt = isDarkTheme ? 1 : 0; + Dwmapi.DwmSetWindowAttribute(hwnd, (uint)Dwmapi.WindowAttribute.UseImmersiveDarkMode, ref isDarkThemeInt, Marshal.SizeOf(typeof(bool))); + + var margins = new Dwmapi.Margins(-1, -1, -1, -1); + Dwmapi.DwmExtendFrameIntoClientArea(hwnd, ref margins); + + var val = pvAttribute; + Dwmapi.DwmSetWindowAttribute(hwnd, dwAttribute, ref val, Marshal.SizeOf(typeof(int))); + } + + public static void EnableMicaBlur(Window window, bool isDarkTheme) + { + EnableDwmBlur(window, isDarkTheme, (uint)Dwmapi.WindowAttribute.MicaEffect, 1); + } + + public static void EnableBackdropMicaBlur(Window window, bool isDarkTheme) + { + EnableDwmBlur(window, isDarkTheme, (uint)Dwmapi.WindowAttribute.SystembackdropType, (int)Dwmapi.SystembackdropType.MainWindow); + } + + [StructLayout(LayoutKind.Sequential)] + public struct WindowCompositionAttributeData + { + public WindowCompositionAttribute Attribute; + public nint Data; + public int SizeOfData; + } + + private enum AccentState + { + AccentDisabled = 0, + AccentEnableGradient = 1, + AccentEnableTransparentgradient = 2, + AccentEnableBlurbehind = 3, + AccentInvalidState = 4, + } + + [StructLayout(LayoutKind.Sequential)] + private struct AccentPolicy + { + public AccentState AccentState; + public int AccentFlags; + public uint GradientColor; + public readonly int AnimationId; + } +} diff --git a/QuickLook.Common/NativeMethods/Dwmapi.cs b/QuickLook.Common/NativeMethods/Dwmapi.cs new file mode 100644 index 0000000..99c1435 --- /dev/null +++ b/QuickLook.Common/NativeMethods/Dwmapi.cs @@ -0,0 +1,54 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Runtime.InteropServices; + +namespace QuickLook.Common.NativeMethods; + +public static class Dwmapi +{ + [StructLayout(LayoutKind.Sequential)] + public struct Margins(int cxLeftWidth, int cxRightWidth, int cyTopHeight, int cyBottomHeight) + { + public int cxLeftWidth = cxLeftWidth; + public int cxRightWidth = cxRightWidth; + public int cyTopHeight = cyTopHeight; + public int cyBottomHeight = cyBottomHeight; + } + + public enum WindowAttribute + { + UseImmersiveDarkMode = 20, + SystembackdropType = 38, + MicaEffect = 1029, + } + + public enum SystembackdropType + { + Auto = 0, + None = 1, + MainWindow = 2, + TransientWindow = 3, + TabbedWindow = 4, + } + + [DllImport("DwmApi.dll")] + public static extern int DwmExtendFrameIntoClientArea(nint hwnd, ref Margins pMarInset); + + [DllImport("dwmapi.dll")] + public static extern int DwmSetWindowAttribute(nint hwnd, uint dwAttribute, ref int pvAttribute, int cbAttribute); +} diff --git a/QuickLook.Common/NativeMethods/Kernel32.cs b/QuickLook.Common/NativeMethods/Kernel32.cs new file mode 100644 index 0000000..1030fb5 --- /dev/null +++ b/QuickLook.Common/NativeMethods/Kernel32.cs @@ -0,0 +1,50 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using Microsoft.Win32.SafeHandles; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace QuickLook.Common.NativeMethods; + +public static class Kernel32 +{ + [DllImport("kernel32.dll")] + public static extern nint LoadLibrary(string lpFileName); + + [DllImport("kernel32.dll")] + public static extern int GetCurrentPackageFullName(ref uint packageFullNameLength, + [MarshalAs(UnmanagedType.LPWStr)] StringBuilder packageFullName); + + [DllImport("kernel32.dll")] + public static extern nint GetCurrentThreadId(); + + [DllImport("kernel32.dll")] + public static extern bool GetProductInfo(int dwOSMajorVersion, int dwOSMinorVersion, int dwSpMajorVersion, + int dwSpMinorVersion, out uint pdwReturnedProductType); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + public static extern SafeFileHandle CreateFile( + [MarshalAs(UnmanagedType.LPWStr)] string filename, + [MarshalAs(UnmanagedType.U4)] FileAccess access, + [MarshalAs(UnmanagedType.U4)] FileShare share, + nint securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero + [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, + [MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes, + nint templateFile); +} diff --git a/QuickLook.Common/NativeMethods/MsCms.cs b/QuickLook.Common/NativeMethods/MsCms.cs new file mode 100644 index 0000000..87748d4 --- /dev/null +++ b/QuickLook.Common/NativeMethods/MsCms.cs @@ -0,0 +1,86 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Runtime.InteropServices; +using System.Text; + +namespace QuickLook.Common.NativeMethods; + +public static class MsCms +{ + [DllImport("mscms.dll", CharSet = CharSet.Auto)] + public static extern bool GetColorDirectory( + [MarshalAs(UnmanagedType.LPWStr)] string pMachineName, + StringBuilder pBuffer, + ref uint pdwSize); + + [DllImport("mscms.dll", CharSet = CharSet.Auto)] + public static extern bool WcsGetUsePerUserProfiles( + [MarshalAs(UnmanagedType.LPTStr)] string deviceName, + uint deviceClass, + out bool usePerUserProfiles); + + [DllImport("mscms.dll", CharSet = CharSet.Auto)] + public static extern bool WcsGetDefaultColorProfileSize( + WcsProfileManagementScope scope, + [MarshalAs(UnmanagedType.LPTStr)] string deviceName, + ColorProfileType colorProfileType, + ColorProfileSubtype colorProfileSubType, + uint dwProfileID, + out uint cbProfileName); + + [DllImport("mscms.dll", CharSet = CharSet.Auto)] + public static extern bool WcsGetDefaultColorProfile( + WcsProfileManagementScope scope, + [MarshalAs(UnmanagedType.LPTStr)] string deviceName, + ColorProfileType colorProfileType, + ColorProfileSubtype colorProfileSubType, + uint dwProfileID, + uint cbProfileName, + StringBuilder pProfileName); + + public enum WcsProfileManagementScope + { + SYSTEM_WIDE, + CURRENT_USER, + } + + public enum ColorProfileType + { + ICC, + DMP, + CAMP, + GMMP, + }; + + public enum ColorProfileSubtype + { + PERCEPTUAL, + RELATIVE_COLORIMETRIC, + SATURATION, + ABSOLUTE_COLORIMETRIC, + NONE, + RGB_WORKING_SPACE, + CUSTOM_WORKING_SPACE, + STANDARD_DISPLAY_COLOR_MODE, + EXTENDED_DISPLAY_COLOR_MODE, + }; + + public const uint CLASS_MONITOR = 0x6d6e7472; // 'mntr' + public const uint CLASS_PRINTER = 0x70727472; // 'prtr' + public const uint CLASS_SCANNER = 0x73636e72; // 'scnr' +} diff --git a/QuickLook.Common/NativeMethods/User32.cs b/QuickLook.Common/NativeMethods/User32.cs new file mode 100644 index 0000000..a97192b --- /dev/null +++ b/QuickLook.Common/NativeMethods/User32.cs @@ -0,0 +1,210 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Text; +using QuickLook.Common.Helpers; + +namespace QuickLook.Common.NativeMethods; + +public static class User32 +{ + public delegate int KeyboardHookProc(int code, int wParam, ref KeyboardHookStruct lParam); + + [DllImport("user32.dll")] + public static extern int MoveWindow(nint hWnd, int x, int y, int nWidth, int nHeight, + [MarshalAs(UnmanagedType.Bool)] bool bRepaint); + + [DllImport("user32.dll")] + public static extern bool SetWindowPos(nint hWnd, nint hWndInsertAfter, int x, int y, int cx, int cy, + uint uFlags); + + [DllImport("user32.dll")] + public static extern nint SetWindowsHookEx(int idHook, KeyboardHookProc callback, nint hInstance, + uint threadId); + + [DllImport("user32.dll")] + public static extern bool UnhookWindowsHookEx(nint hInstance); + + [DllImport("user32.dll")] + public static extern int CallNextHookEx(nint idHook, int nCode, int wParam, ref KeyboardHookStruct lParam); + + [DllImport("user32.dll")] + public static extern nint SetWindowLong(nint hWnd, int nIndex, int dwNewLong); + + [DllImport("user32.dll")] + public static extern int GetWindowLong(nint hWnd, int nIndex); + + [DllImport("user32.dll")] + public static extern nint GetAncestor(nint hwnd, uint gaFlags); + + [DllImport("user32.dll")] + public static extern nint GetForegroundWindow(); + + [DllImport("user32.dll")] + public static extern nint GetDesktopWindow(); + + [DllImport("user32.dll")] + public static extern bool GetWindowRect(nint hwnd, out RECT lpRect); + + [DllImport("user32.dll")] + public static extern nint GetWindowThreadProcessId(nint hWnd, nint processId); + + [DllImport("user32.dll")] + public static extern nint GetWindowThreadProcessId(nint hWnd, out uint processId); + + [DllImport("user32.dll")] + public static extern nint AttachThreadInput(nint idAttach, nint idAttachTo, bool fAttach); + + [DllImport("user32.dll")] + public static extern nint GetFocus(); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern int GetClassName(nint hWnd, StringBuilder lpClassName, int nMaxCount); + + [DllImport("user32.dll")] + public static extern nint GetParent(nint hWnd); + + [DllImport("user32.dll")] + public static extern int SetWindowCompositionAttribute(nint hwnd, + ref WindowHelper.WindowCompositionAttributeData data); + + [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] + public static extern int GetDeviceCaps(nint hDC, DeviceCap nIndex); + + [DllImport("user32.dll")] + public static extern nint MonitorFromWindow(nint hWnd, MonitorDefaults dwFlags); + + [DllImport("user32.dll")] + public extern static bool GetMonitorInfo(nint hMonitor, ref MONITORINFOEX lpmi); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAYDEVICE lpDisplayDevice, uint dwFlags); + + public enum MonitorDefaults + { + TONULL = 0, + TOPRIMARY = 1, + TONEAREST = 2 + } + + public enum DeviceCap + { + /// + /// Logical pixels inch in X + /// + LOGPIXELSX = 88, + + /// + /// Logical pixels inch in Y + /// + LOGPIXELSY = 90 + } + + [SuppressMessage("ReSharper", "InconsistentNaming")] + public struct KeyboardHookStruct + { + public int vkCode; + public int scanCode; + public int flags; + public int time; + public int dwExtraInfo; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RECT + { + public int Left; + public int Top; + public int Right; + public int Bottom; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MONITORINFOEX + { + public uint cbSize; + public RECT rcMonitor; + public RECT rcWork; + public uint dwFlags; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string szDevice; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public struct DISPLAYDEVICE + { + public uint cb; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string DeviceName; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string DeviceString; + + public uint StateFlags; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string DeviceID; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string DeviceKey; + } + + // ReSharper disable InconsistentNaming + public static readonly nint HWND_TOPMOST = -1; + + public static readonly nint HWND_NOTOPMOST = -2; + public static readonly nint HWND_TOP = 0; + public static readonly nint HWND_BOTTOM = 1; + + public const uint SWP_NOSIZE = 0x0001; + public const uint SWP_NOMOVE = 0x0002; + public const uint SWP_NOZORDER = 0x0004; + public const uint SWP_NOREDRAW = 0x0008; + public const uint SWP_NOACTIVATE = 0x0010; + public const uint SWP_DRAWFRAME = 0x0020; + public const uint SWP_FRAMECHANGED = 0x0020; + public const uint SWP_SHOWWINDOW = 0x0040; + public const uint SWP_HIDEWINDOW = 0x0080; + public const uint SWP_NOCOPYBITS = 0x0100; + public const uint SWP_NOOWNERZORDER = 0x0200; + public const uint SWP_NOREPOSITION = 0x0200; + public const uint SWP_NOSENDCHANGING = 0x0400; + public const uint SWP_DEFERERASE = 0x2000; + public const uint SWP_ASYNCWINDOWPOS = 0x4000; + + public const int WH_KEYBOARD_LL = 13; + public const int WM_KEYDOWN = 0x100; + public const int WM_KEYUP = 0x101; + public const int WM_SYSKEYDOWN = 0x104; + public const int WM_SYSKEYUP = 0x105; + public const int GWL_STYLE = -16; + public const int GWL_EXSTYLE = -20; + public const int WS_SYSMENU = 0x00080000; + public const int WS_MINIMIZEBOX = 0x00020000; + public const int WS_MAXIMIZEBOX = 0x00010000; + public const int WS_EX_NOACTIVATE = 0x08000000; + + public const uint GA_PARENT = 1; + public const uint GA_ROOT = 2; + public const uint GA_ROOTOWNER = 3; + // ReSharper restore InconsistentNaming +} diff --git a/QuickLook.Common/Plugin/ContextObject.cs b/QuickLook.Common/Plugin/ContextObject.cs new file mode 100644 index 0000000..f1e5645 --- /dev/null +++ b/QuickLook.Common/Plugin/ContextObject.cs @@ -0,0 +1,266 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using QuickLook.Common.Annotations; +using QuickLook.Common.Helpers; +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Windows; + +namespace QuickLook.Common.Plugin; + +/// +/// A runtime object which allows interaction between this plugin and QuickLook. +/// +public class ContextObject : INotifyPropertyChanged +{ + private bool _canResize = true; + private bool _fullWindowDragging; + private bool _isBusy; + private string _title = string.Empty; + private bool _titlebarAutoHide; + private bool _titlebarBlurVisibility; + private bool _titlebarColourVisibility = true; + private bool _titlebarOverlap; + private Themes _theme = Themes.None; + private object _viewerContent; + private string _colorProfileName = null; + private bool _isBlocked; + + /// + /// Get the instance of Viewer window. + /// + public object Source { get; set; } + + /// + /// Get or set the title of Viewer window. + /// + public string Title + { + get => _title; + set + { + _title = value; + OnPropertyChanged(); + } + } + + /// + /// Get or set the viewer content control. + /// + public object ViewerContent + { + get => _viewerContent; + set + { + _viewerContent = value; + OnPropertyChanged(); + } + } + + /// + /// Show or hide the busy indicator icon. + /// + public bool IsBusy + { + get => _isBusy; + set + { + _isBusy = value; + OnPropertyChanged(); + } + } + + /// + /// Set the exact size you want. + /// + public Size PreferredSize { get; set; } = new Size { Width = 800, Height = 600 }; + + /// + /// Set whether user are allowed to resize the viewer window. + /// + public bool CanResize + { + get => _canResize; + set + { + _canResize = value; + OnPropertyChanged(); + } + } + + /// + /// Set whether the full viewer window can be used for mouse dragging. + /// + public bool FullWindowDragging + { + get => _fullWindowDragging; + set + { + _fullWindowDragging = value; + OnPropertyChanged(); + } + } + + /// + /// Set whether the viewer content is overlapped by the title bar + /// + public bool TitlebarOverlap + { + get => _titlebarOverlap; + set + { + _titlebarOverlap = value; + OnPropertyChanged(); + } + } + + /// + /// Set whether the title bar shows a blurred background + /// + public bool TitlebarBlurVisibility + { + get => _titlebarBlurVisibility; + set + { + if (value == _titlebarBlurVisibility) return; + _titlebarBlurVisibility = value; + OnPropertyChanged(); + } + } + + /// + /// Set whether the title bar shows a colour overlay + /// + public bool TitlebarColourVisibility + { + get => _titlebarColourVisibility; + set + { + if (value == _titlebarColourVisibility) return; + _titlebarColourVisibility = value; + OnPropertyChanged(); + } + } + + /// + /// Should the titlebar hides itself after a short period of inactivity? + /// + public bool TitlebarAutoHide + { + get => _titlebarAutoHide; + set + { + if (value == _titlebarAutoHide) return; + _titlebarAutoHide = value; + OnPropertyChanged(); + } + } + + /// + /// Switch to dark theme? + /// + public Themes Theme + { + get => _theme; + set + { + _theme = value; + OnPropertyChanged(); + } + } + + /// + /// The color profile of the monitor that will host the preview window + /// + public string ColorProfileName + { + get => _colorProfileName; + set + { + _colorProfileName = value; + OnPropertyChanged(); + } + } + + /// + /// Get or set whether to block showing the preview window. + /// + public bool IsBlocked + { + get => _isBlocked; + set + { + _isBlocked = value; + OnPropertyChanged(); + } + } + + public event PropertyChangedEventHandler PropertyChanged; + + /// + /// Set the size of viewer window, scale or shrink to fit (to screen resolution). + /// The window can take maximum (maxRatio*resolution) space. + /// + /// The desired size. + /// The maximum percent (over screen resolution) it can take. + public double SetPreferredSizeFit(Size size, double maxRatio) + { + if (maxRatio > 1) + maxRatio = 1; + + var max = WindowHelper.GetCurrentDesktopSize(); + + var widthRatio = max.Width * maxRatio / size.Width; + var heightRatio = max.Height * maxRatio / size.Height; + + var ratio = Math.Min(widthRatio, heightRatio); + if (ratio > 1) ratio = 1; + + PreferredSize = new Size { Width = size.Width * ratio, Height = size.Height * ratio }; + + return ratio; + } + + public void Reset() + { + Title = string.Empty; + // set to False to prevent showing loading icon + IsBusy = false; + PreferredSize = new Size(); + CanResize = true; + FullWindowDragging = false; + + Theme = Themes.None; + TitlebarOverlap = false; + TitlebarAutoHide = false; + TitlebarBlurVisibility = false; + TitlebarColourVisibility = true; + + ViewerContent = null; + + ColorProfileName = null; + IsBlocked = false; + } + + [NotifyPropertyChangedInvocator] + protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } +} diff --git a/QuickLook.Common/Plugin/IViewer.cs b/QuickLook.Common/Plugin/IViewer.cs new file mode 100644 index 0000000..e605fe2 --- /dev/null +++ b/QuickLook.Common/Plugin/IViewer.cs @@ -0,0 +1,61 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +namespace QuickLook.Common.Plugin; + +/// +/// Interface implemented by every QuickLook.Plugin +/// +public interface IViewer +{ + /// + /// Set the priority of this plugin. A plugin with a higher priority may override one with lower priority. + /// Set this to int.MaxValue for a maximum priority, int.MinValue for minimum. + /// + public int Priority { get; } + + /// + /// Do ont-time job when application starts. You may extract nessessary resource here. + /// + public void Init(); + + /// + /// Determine whether this plugin can open this file. Please also check the file header, if applicable. + /// + /// The full path of the target file. + public bool CanHandle(string path); + + /// + /// Do some preparation stuff before the window is showing. Please not do any work that costs a lot of time. + /// + /// The full path of the target file. + /// A runtime object which allows interaction between this plugin and QuickLook. + public void Prepare(string path, ContextObject context); + + /// + /// Start the loading process. During the process a busy indicator will be shown. Finish by setting context.IsBusy to + /// false. + /// + /// The full path of the target file. + /// A runtime object which allows interaction between this plugin and QuickLook. + public void View(string path, ContextObject context); + + /// + /// Release any unmanaged resource here. + /// + public void Cleanup(); +} diff --git a/QuickLook.Common/Plugin/MoreMenu/IMenuItem.cs b/QuickLook.Common/Plugin/MoreMenu/IMenuItem.cs new file mode 100644 index 0000000..6eeb0bf --- /dev/null +++ b/QuickLook.Common/Plugin/MoreMenu/IMenuItem.cs @@ -0,0 +1,77 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Collections.Generic; +using System.ComponentModel; +using System.Windows.Input; + +namespace QuickLook.Common.Plugin.MoreMenu; + +/// +/// Represents a menu item that can be added to the QuickLook viewer's context menu. +/// +public interface IMenuItem : INotifyPropertyChanged +{ + /// + /// Gets the icon for the menu item. Can be a string (for Unicode symbols) + /// String, check from https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font + /// ImageSource, or null for no icon. + /// + public object Icon { get; set; } + + /// + /// Gets the display text for the menu item. + /// + public object Header { get; set; } + + /// + /// Gets the collection of menu items. + /// + public IEnumerable MenuItems { get; set; } + + /// + /// Gets a value indicating whether the menu item is visible. + /// This allows dynamic show/hide based on file context. + /// + public bool IsVisible { get; set; } + + /// + /// Gets a value indicating whether the menu item is enabled. + /// + public bool IsEnabled { get; set; } + + /// + /// Gets the command to execute when the menu item is clicked. + /// + public ICommand Command { get; set; } + + /// + /// Gets the command parameter for the Command. + /// + public object CommandParameter { get; set; } + + /// + /// Gets the tooltip text for the menu item. + /// + public string ToolTip { get; set; } + + /// + /// Gets a value indicating whether this menu item represents a separator. + /// When true, other properties are ignored and a separator line is shown. + /// + public bool IsSeparator { get; set; } +} diff --git a/QuickLook.Common/Plugin/MoreMenu/IMoreMenu.cs b/QuickLook.Common/Plugin/MoreMenu/IMoreMenu.cs new file mode 100644 index 0000000..32aa413 --- /dev/null +++ b/QuickLook.Common/Plugin/MoreMenu/IMoreMenu.cs @@ -0,0 +1,33 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Collections.Generic; + +namespace QuickLook.Common.Plugin.MoreMenu; + +/// +/// Interface implemented by QuickLook plugins that want to provide custom context menu items. +/// Plugins implementing this interface can add menu items to the viewer's title bar context menu. +/// +public interface IMoreMenu +{ + /// + /// Gets the collection of menu items that this plugin provides. + /// This property will be queried after the Prepare method is called. + /// + public IEnumerable MenuItems { get; } +} diff --git a/QuickLook.Common/Plugin/MoreMenu/IMoreMenuExtended.cs b/QuickLook.Common/Plugin/MoreMenu/IMoreMenuExtended.cs new file mode 100644 index 0000000..b9193d4 --- /dev/null +++ b/QuickLook.Common/Plugin/MoreMenu/IMoreMenuExtended.cs @@ -0,0 +1,24 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +namespace QuickLook.Common.Plugin.MoreMenu; + +/// +/// Indicates that the extended version of IMoreMenu means that +/// the insertion operation will be performed regardless of whether it is a matching plugin or not. +/// +public interface IMoreMenuExtended : IMoreMenu; diff --git a/QuickLook.Common/Plugin/MoreMenu/MoreMenuItem.cs b/QuickLook.Common/Plugin/MoreMenu/MoreMenuItem.cs new file mode 100644 index 0000000..fe641fc --- /dev/null +++ b/QuickLook.Common/Plugin/MoreMenu/MoreMenuItem.cs @@ -0,0 +1,135 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using QuickLook.Common.Annotations; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Windows.Input; + +namespace QuickLook.Common.Plugin.MoreMenu; + +/// +/// Base class for QuickLook menu items that provides common functionality +/// and implements INotifyPropertyChanged for dynamic property updates. +/// +public class MoreMenuItem : IMenuItem +{ + private object _icon; + private object _header; + private IEnumerable _menuItems; + private bool _isVisible = true; + private bool _isEnabled = true; + private ICommand _command; + private object _commandParameter; + private string _toolTip; + private bool _isSeparator; + + /// + public virtual object Icon + { + get => _icon; + set => SetProperty(ref _icon, value); + } + + /// + public virtual object Header + { + get => _header; + set => SetProperty(ref _header, value); + } + + /// + public IEnumerable MenuItems + { + get => _menuItems; + set => SetProperty(ref _menuItems, value); + } + + /// + public virtual bool IsVisible + { + get => _isVisible; + set => SetProperty(ref _isVisible, value); + } + + /// + public virtual bool IsEnabled + { + get => _isEnabled; + set => SetProperty(ref _isEnabled, value); + } + + /// + public virtual ICommand Command + { + get => _command; + set => SetProperty(ref _command, value); + } + + /// + public virtual object CommandParameter + { + get => _commandParameter; + set => SetProperty(ref _commandParameter, value); + } + + /// + public virtual string ToolTip + { + get => _toolTip; + set => SetProperty(ref _toolTip, value); + } + + /// + public virtual bool IsSeparator + { + get => _isSeparator; + set => SetProperty(ref _isSeparator, value); + } + + /// + public event PropertyChangedEventHandler PropertyChanged; + + /// + /// Raises the PropertyChanged event for the specified property. + /// + /// The name of the property that changed. + [NotifyPropertyChangedInvocator] + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + /// + /// Sets the property value and raises PropertyChanged if the value has changed. + /// + /// The type of the property. + /// The backing field for the property. + /// The new value. + /// The name of the property. + /// True if the property value was changed; otherwise, false. + protected bool SetProperty(ref T field, T value, [CallerMemberName] string propertyName = null) + { + if (Equals(field, value)) + return false; + + field = value; + OnPropertyChanged(propertyName); + return true; + } +} diff --git a/QuickLook.Common/Plugin/Themes.cs b/QuickLook.Common/Plugin/Themes.cs new file mode 100644 index 0000000..f407e45 --- /dev/null +++ b/QuickLook.Common/Plugin/Themes.cs @@ -0,0 +1,25 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +namespace QuickLook.Common.Plugin; + +public enum Themes +{ + None, + Dark, + Light, +} diff --git a/QuickLook.Common/Properties/Annotations.cs b/QuickLook.Common/Properties/Annotations.cs new file mode 100644 index 0000000..925c9aa --- /dev/null +++ b/QuickLook.Common/Properties/Annotations.cs @@ -0,0 +1,1241 @@ +// Copyright © 2017-2026 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; + +#pragma warning disable 1591 +// ReSharper disable UnusedMember.Global +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable IntroduceOptionalParameters.Global +// ReSharper disable MemberCanBeProtected.Global +// ReSharper disable InconsistentNaming + +namespace QuickLook.Common.Annotations +{ + /// + /// Indicates that the value of the marked element could be null sometimes, + /// so the check for null is necessary before its usage. + /// + /// + /// + /// [CanBeNull] object Test() => null; + /// + /// void UseTest() { + /// var p = Test(); + /// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException' + /// } + /// + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event | + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)] + public sealed class CanBeNullAttribute : Attribute + { + } + + /// + /// Indicates that the value of the marked element could never be null. + /// + /// + /// + /// [NotNull] object Foo() { + /// return null; // Warning: Possible 'null' assignment + /// } + /// + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event | + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)] + public sealed class NotNullAttribute : Attribute + { + } + + /// + /// Can be appplied to symbols of types derived from IEnumerable as well as to symbols of Task + /// and Lazy classes to indicate that the value of a collection item, of the Task.Result property + /// or of the Lazy.Value property can never be null. + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field)] + public sealed class ItemNotNullAttribute : Attribute + { + } + + /// + /// Can be appplied to symbols of types derived from IEnumerable as well as to symbols of Task + /// and Lazy classes to indicate that the value of a collection item, of the Task.Result property + /// or of the Lazy.Value property can be null. + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Delegate | AttributeTargets.Field)] + public sealed class ItemCanBeNullAttribute : Attribute + { + } + + /// + /// Indicates that the marked method builds string by format pattern and (optional) arguments. + /// Parameter, which contains format string, should be given in constructor. The format string + /// should be in -like form. + /// + /// + /// + /// [StringFormatMethod("message")] + /// void ShowError(string message, params object[] args) { /* do something */ } + /// + /// void Foo() { + /// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string + /// } + /// + /// + [AttributeUsage( + AttributeTargets.Constructor | AttributeTargets.Method | + AttributeTargets.Property | AttributeTargets.Delegate)] + public sealed class StringFormatMethodAttribute : Attribute + { + /// + /// Specifies which parameter of an annotated method should be treated as format-string + /// + public StringFormatMethodAttribute([NotNull] string formatParameterName) + { + FormatParameterName = formatParameterName; + } + + [NotNull] + public string FormatParameterName { get; } + } + + /// + /// For a parameter that is expected to be one of the limited set of values. + /// Specify fields of which type should be used as values for this parameter. + /// + [AttributeUsage( + AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field, + AllowMultiple = true)] + public sealed class ValueProviderAttribute : Attribute + { + public ValueProviderAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] + public string Name { get; } + } + + /// + /// Indicates that the function argument should be string literal and match one + /// of the parameters of the caller function. For example, ReSharper annotates + /// the parameter of . + /// + /// + /// + /// void Foo(string param) { + /// if (param == null) + /// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol + /// } + /// + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class InvokerParameterNameAttribute : Attribute + { + } + + /// + /// Indicates that the method is contained in a type that implements + /// System.ComponentModel.INotifyPropertyChanged interface and this method + /// is used to notify that some property value changed. + /// + /// + /// The method should be non-static and conform to one of the supported signatures: + /// + /// + /// NotifyChanged(string) + /// + /// + /// NotifyChanged(params string[]) + /// + /// + /// NotifyChanged{T}(Expression{Func{T}}) + /// + /// + /// NotifyChanged{T,U}(Expression{Func{T,U}}) + /// + /// + /// SetProperty{T}(ref T, T, string) + /// + /// + /// + /// + /// + /// public class Foo : INotifyPropertyChanged { + /// public event PropertyChangedEventHandler PropertyChanged; + /// + /// [NotifyPropertyChangedInvocator] + /// protected virtual void NotifyChanged(string propertyName) { ... } + /// + /// string _name; + /// + /// public string Name { + /// get { return _name; } + /// set { _name = value; NotifyChanged("LastName"); /* Warning */ } + /// } + /// } + /// + /// Examples of generated notifications: + /// + /// + /// NotifyChanged("Property") + /// + /// + /// NotifyChanged(() => Property) + /// + /// + /// NotifyChanged((VM x) => x.Property) + /// + /// + /// SetProperty(ref myField, value, "Property") + /// + /// + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute + { + public NotifyPropertyChangedInvocatorAttribute() + { + } + + public NotifyPropertyChangedInvocatorAttribute([NotNull] string parameterName) + { + ParameterName = parameterName; + } + + [CanBeNull] + public string ParameterName { get; } + } + + /// + /// Describes dependency between method input and output. + /// + /// + ///

Function Definition Table syntax:

+ /// + /// FDT ::= FDTRow [;FDTRow]* + /// FDTRow ::= Input => Output | Output <= Input + /// Input ::= ParameterName: Value [, Input]* + /// Output ::= [ParameterName: Value]* {halt|stop|void|nothing|Value} + /// Value ::= true | false | null | notnull | canbenull + /// + /// If method has single input parameter, it's name could be omitted.
+ /// Using halt (or void/nothing, which is the same) for method output + /// means that the methos doesn't return normally (throws or terminates the process).
+ /// Value canbenull is only applicable for output parameters.
+ /// You can use multiple [ContractAnnotation] for each FDT row, or use single attribute + /// with rows separated by semicolon. There is no notion of order rows, all rows are checked + /// for applicability and applied per each program state tracked by R# analysis.
+ ///
+ /// + /// + /// + /// + /// [ContractAnnotation("=> halt")] + /// public void TerminationMethod() + /// + /// + /// + /// + /// [ContractAnnotation("halt <= condition: false")] + /// public void Assert(bool condition, string text) // regular assertion method + /// + /// + /// + /// + /// [ContractAnnotation("s:null => true")] + /// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty() + /// + /// + /// + /// + /// // A method that returns null if the parameter is null, + /// // and not null if the parameter is not null + /// [ContractAnnotation("null => null; notnull => notnull")] + /// public object Transform(object data) + /// + /// + /// + /// + /// [ContractAnnotation("=> true, result: notnull; => false, result: null")] + /// public bool TryParse(string s, out Person result) + /// + /// + /// + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + public sealed class ContractAnnotationAttribute : Attribute + { + public ContractAnnotationAttribute([NotNull] string contract) + : this(contract, false) + { + } + + public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates) + { + Contract = contract; + ForceFullStates = forceFullStates; + } + + [NotNull] + public string Contract { get; } + + public bool ForceFullStates { get; } + } + + /// + /// Indicates that marked element should be localized or not. + /// + /// + /// + /// [LocalizationRequiredAttribute(true)] + /// class Foo { + /// string str = "my string"; // Warning: Localizable string + /// } + /// + /// + [AttributeUsage(AttributeTargets.All)] + public sealed class LocalizationRequiredAttribute : Attribute + { + public LocalizationRequiredAttribute() : this(true) + { + } + + public LocalizationRequiredAttribute(bool required) + { + Required = required; + } + + public bool Required { get; } + } + + /// + /// Indicates that the value of the marked type (or its derivatives) + /// cannot be compared using '==' or '!=' operators and Equals() + /// should be used instead. However, using '==' or '!=' for comparison + /// with null is always permitted. + /// + /// + /// + /// [CannotApplyEqualityOperator] + /// class NoEquality { } + /// + /// class UsesNoEquality { + /// void Test() { + /// var ca1 = new NoEquality(); + /// var ca2 = new NoEquality(); + /// if (ca1 != null) { // OK + /// bool condition = ca1 == ca2; // Warning + /// } + /// } + /// } + /// + /// + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Struct)] + public sealed class CannotApplyEqualityOperatorAttribute : Attribute + { + } + + /// + /// When applied to a target attribute, specifies a requirement for any type marked + /// with the target attribute to implement or inherit specific type or types. + /// + /// + /// + /// [BaseTypeRequired(typeof(IComponent)] // Specify requirement + /// class ComponentAttribute : Attribute { } + /// + /// [Component] // ComponentAttribute requires implementing IComponent interface + /// class MyComponent : IComponent { } + /// + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + [BaseTypeRequired(typeof(Attribute))] + public sealed class BaseTypeRequiredAttribute : Attribute + { + public BaseTypeRequiredAttribute([NotNull] Type baseType) + { + BaseType = baseType; + } + + [NotNull] + public Type BaseType { get; } + } + + /// + /// Indicates that the marked symbol is used implicitly (e.g. via reflection, in external library), + /// so this symbol will not be marked as unused (as well as by other usage inspections). + /// + [AttributeUsage(AttributeTargets.All)] + public sealed class UsedImplicitlyAttribute : Attribute + { + public UsedImplicitlyAttribute() + : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) + { + } + + public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) + : this(useKindFlags, ImplicitUseTargetFlags.Default) + { + } + + public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) + : this(ImplicitUseKindFlags.Default, targetFlags) + { + } + + public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) + { + UseKindFlags = useKindFlags; + TargetFlags = targetFlags; + } + + public ImplicitUseKindFlags UseKindFlags { get; } + + public ImplicitUseTargetFlags TargetFlags { get; } + } + + /// + /// Should be used on attributes and causes ReSharper to not mark symbols marked with such attributes + /// as unused (as well as by other usage inspections) + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.GenericParameter)] + public sealed class MeansImplicitUseAttribute : Attribute + { + public MeansImplicitUseAttribute() + : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) + { + } + + public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags) + : this(useKindFlags, ImplicitUseTargetFlags.Default) + { + } + + public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags) + : this(ImplicitUseKindFlags.Default, targetFlags) + { + } + + public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) + { + UseKindFlags = useKindFlags; + TargetFlags = targetFlags; + } + + [UsedImplicitly] + public ImplicitUseKindFlags UseKindFlags { get; } + + [UsedImplicitly] + public ImplicitUseTargetFlags TargetFlags { get; } + } + + [Flags] + public enum ImplicitUseKindFlags + { + Default = Access | Assign | InstantiatedWithFixedConstructorSignature, + /// Only entity marked with attribute considered used. + Access = 1, + /// Indicates implicit assignment to a member. + Assign = 2, + /// + /// Indicates implicit instantiation of a type with fixed constructor signature. + /// That means any unused constructor parameters won't be reported as such. + /// + InstantiatedWithFixedConstructorSignature = 4, + /// Indicates implicit instantiation of a type. + InstantiatedNoFixedConstructorSignature = 8 + } + + /// + /// Specify what is considered used implicitly when marked + /// with or . + /// + [Flags] + public enum ImplicitUseTargetFlags + { + Default = Itself, + Itself = 1, + /// Members of entity marked with attribute are considered used. + Members = 2, + /// Entity marked with attribute and all its members considered used. + WithMembers = Itself | Members + } + + /// + /// This attribute is intended to mark publicly available API + /// which should not be removed and so is treated as used. + /// + [MeansImplicitUse(ImplicitUseTargetFlags.WithMembers)] + public sealed class PublicAPIAttribute : Attribute + { + public PublicAPIAttribute() + { + } + + public PublicAPIAttribute([NotNull] string comment) + { + Comment = comment; + } + + [CanBeNull] + public string Comment { get; } + } + + /// + /// Tells code analysis engine if the parameter is completely handled when the invoked method is on stack. + /// If the parameter is a delegate, indicates that delegate is executed while the method is executed. + /// If the parameter is an enumerable, indicates that it is enumerated while the method is executed. + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class InstantHandleAttribute : Attribute + { + } + + /// + /// Indicates that a method does not make any observable state changes. + /// The same as System.Diagnostics.Contracts.PureAttribute. + /// + /// + /// + /// [Pure] int Multiply(int x, int y) => x * y; + /// + /// void M() { + /// Multiply(123, 42); // Waring: Return value of pure method is not used + /// } + /// + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class PureAttribute : Attribute + { + } + + /// + /// Indicates that the return value of method invocation must be used. + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class MustUseReturnValueAttribute : Attribute + { + public MustUseReturnValueAttribute() + { + } + + public MustUseReturnValueAttribute([NotNull] string justification) + { + Justification = justification; + } + + [CanBeNull] + public string Justification { get; } + } + + /// + /// Indicates the type member or parameter of some type, that should be used instead of all other ways + /// to get the value that type. This annotation is useful when you have some "context" value evaluated + /// and stored somewhere, meaning that all other ways to get this value must be consolidated with existing one. + /// + /// + /// + /// class Foo { + /// [ProvidesContext] IBarService _barService = ...; + /// + /// void ProcessNode(INode node) { + /// DoSomething(node, node.GetGlobalServices().Bar); + /// // ^ Warning: use value of '_barService' field + /// } + /// } + /// + /// + [AttributeUsage( + AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Method | + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | + AttributeTargets.GenericParameter)] + public sealed class ProvidesContextAttribute : Attribute + { + } + + /// + /// Indicates that a parameter is a path to a file or a folder within a web project. + /// Path can be relative or absolute, starting from web root (~). + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class PathReferenceAttribute : Attribute + { + public PathReferenceAttribute() + { + } + + public PathReferenceAttribute([NotNull] [PathReference] string basePath) + { + BasePath = basePath; + } + + [CanBeNull] + public string BasePath { get; } + } + + /// + /// An extension method marked with this attribute is processed by ReSharper code completion + /// as a 'Source Template'. When extension method is completed over some expression, it's source code + /// is automatically expanded like a template at call site. + /// + /// + /// Template method body can contain valid source code and/or special comments starting with '$'. + /// Text inside these comments is added as source code when the template is applied. Template parameters + /// can be used either as additional method parameters or as identifiers wrapped in two '$' signs. + /// Use the attribute to specify macros for parameters. + /// + /// + /// In this example, the 'forEach' method is a source template available over all values + /// of enumerable types, producing ordinary C# 'foreach' statement and placing caret inside block: + /// + /// [SourceTemplate] + /// public static void forEach<T>(this IEnumerable<T> xs) { + /// foreach (var x in xs) { + /// //$ $END$ + /// } + /// } + /// + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class SourceTemplateAttribute : Attribute + { + } + + /// + /// Allows specifying a macro for a parameter of a source template. + /// + /// + /// You can apply the attribute on the whole method or on any of its additional parameters. The macro expression + /// is defined in the property. When applied on a method, the target + /// template parameter is defined in the property. To apply the macro silently + /// for the parameter, set the property value = -1. + /// + /// + /// Applying the attribute on a source template method: + /// + /// [SourceTemplate, Macro(Target = "item", Expression = "suggestVariableName()")] + /// public static void forEach<T>(this IEnumerable<T> collection) { + /// foreach (var item in collection) { + /// //$ $END$ + /// } + /// } + /// + /// Applying the attribute on a template method parameter: + /// + /// [SourceTemplate] + /// public static void something(this Entity x, [Macro(Expression = "guid()", Editable = -1)] string newguid) { + /// /*$ var $x$Id = "$newguid$" + x.ToString(); + /// x.DoSomething($x$Id); */ + /// } + /// + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, AllowMultiple = true)] + public sealed class MacroAttribute : Attribute + { + /// + /// Allows specifying a macro that will be executed for a source template + /// parameter when the template is expanded. + /// + [CanBeNull] + public string Expression { get; set; } + + /// + /// Allows specifying which occurrence of the target parameter becomes editable when the template is deployed. + /// + /// + /// If the target parameter is used several times in the template, only one occurrence becomes editable; + /// other occurrences are changed synchronously. To specify the zero-based index of the editable occurrence, + /// use values >= 0. To make the parameter non-editable when the template is expanded, use -1. + /// + /// > + public int Editable { get; set; } + + /// + /// Identifies the target parameter of a source template if the + /// is applied on a template method. + /// + [CanBeNull] + public string Target { get; set; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = + true)] + public sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute + { + public AspMvcAreaMasterLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] + public string Format { get; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = + true)] + public sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute + { + public AspMvcAreaPartialViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] + public string Format { get; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = + true)] + public sealed class AspMvcAreaViewLocationFormatAttribute : Attribute + { + public AspMvcAreaViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] + public string Format { get; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = + true)] + public sealed class AspMvcMasterLocationFormatAttribute : Attribute + { + public AspMvcMasterLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] + public string Format { get; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = + true)] + public sealed class AspMvcPartialViewLocationFormatAttribute : Attribute + { + public AspMvcPartialViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] + public string Format { get; } + } + + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = + true)] + public sealed class AspMvcViewLocationFormatAttribute : Attribute + { + public AspMvcViewLocationFormatAttribute([NotNull] string format) + { + Format = format; + } + + [NotNull] + public string Format { get; } + } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC action. If applied to a method, the MVC action name is calculated + /// implicitly from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcActionAttribute : Attribute + { + public AspMvcActionAttribute() + { + } + + public AspMvcActionAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [CanBeNull] + public string AnonymousProperty { get; } + } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC area. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String). + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcAreaAttribute : Attribute + { + public AspMvcAreaAttribute() + { + } + + public AspMvcAreaAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [CanBeNull] + public string AnonymousProperty { get; } + } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter is + /// an MVC controller. If applied to a method, the MVC controller name is calculated + /// implicitly from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String, String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcControllerAttribute : Attribute + { + public AspMvcControllerAttribute() + { + } + + public AspMvcControllerAttribute([NotNull] string anonymousProperty) + { + AnonymousProperty = anonymousProperty; + } + + [CanBeNull] + public string AnonymousProperty { get; } + } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC Master. Use this attribute + /// for custom wrappers similar to System.Web.Mvc.Controller.View(String, String). + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcMasterAttribute : Attribute + { + } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC model type. Use this attribute + /// for custom wrappers similar to System.Web.Mvc.Controller.View(String, Object). + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcModelTypeAttribute : Attribute + { + } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter is an MVC + /// partial view. If applied to a method, the MVC partial view name is calculated implicitly + /// from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper, String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcPartialViewAttribute : Attribute + { + } + + /// + /// ASP.NET MVC attribute. Allows disabling inspections for MVC views within a class or a method. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] + public sealed class AspMvcSuppressViewErrorAttribute : Attribute + { + } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.DisplayExtensions.DisplayForModel(HtmlHelper, String). + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcDisplayTemplateAttribute : Attribute + { + } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC editor template. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.EditorExtensions.EditorForModel(HtmlHelper, String). + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcEditorTemplateAttribute : Attribute + { + } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC template. + /// Use this attribute for custom wrappers similar to + /// System.ComponentModel.DataAnnotations.UIHintAttribute(System.String). + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcTemplateAttribute : Attribute + { + } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC view component. If applied to a method, the MVC view name is calculated implicitly + /// from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Controller.View(Object). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcViewAttribute : Attribute + { + } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC view component name. + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcViewComponentAttribute : Attribute + { + } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC view component view. If applied to a method, the MVC view component view name is default. + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcViewComponentViewAttribute : Attribute + { + } + + /// + /// ASP.NET MVC attribute. When applied to a parameter of an attribute, + /// indicates that this parameter is an MVC action name. + /// + /// + /// + /// [ActionName("Foo")] + /// public ActionResult Login(string returnUrl) { + /// ViewBag.ReturnUrl = Url.Action("Foo"); // OK + /// return RedirectToAction("Bar"); // Error: Cannot resolve action + /// } + /// + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] + public sealed class AspMvcActionSelectorAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field)] + public sealed class HtmlElementAttributesAttribute : Attribute + { + public HtmlElementAttributesAttribute() + { + } + + public HtmlElementAttributesAttribute([NotNull] string name) + { + Name = name; + } + + [CanBeNull] + public string Name { get; } + } + + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] + public sealed class HtmlAttributeValueAttribute : Attribute + { + public HtmlAttributeValueAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] + public string Name { get; } + } + + /// + /// Razor attribute. Indicates that a parameter or a method is a Razor section. + /// Use this attribute for custom wrappers similar to + /// System.Web.WebPages.WebPageBase.RenderSection(String). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class RazorSectionAttribute : Attribute + { + } + + /// + /// Indicates how method, constructor invocation or property access + /// over collection type affects content of the collection. + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property)] + public sealed class CollectionAccessAttribute : Attribute + { + public CollectionAccessAttribute(CollectionAccessType collectionAccessType) + { + CollectionAccessType = collectionAccessType; + } + + public CollectionAccessType CollectionAccessType { get; } + } + + [Flags] + public enum CollectionAccessType + { + /// Method does not use or modify content of the collection. + None = 0, + /// Method only reads content of the collection but does not modify it. + Read = 1, + /// Method can change content of the collection but does not add new elements. + ModifyExistingContent = 2, + /// Method can add new elements to the collection. + UpdatedContent = ModifyExistingContent | 4 + } + + /// + /// Indicates that the marked method is assertion method, i.e. it halts control flow if + /// one of the conditions is satisfied. To set the condition, mark one of the parameters with + /// attribute. + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class AssertionMethodAttribute : Attribute + { + } + + /// + /// Indicates the condition parameter of the assertion method. The method itself should be + /// marked by attribute. The mandatory argument of + /// the attribute is the assertion type. + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AssertionConditionAttribute : Attribute + { + public AssertionConditionAttribute(AssertionConditionType conditionType) + { + ConditionType = conditionType; + } + + public AssertionConditionType ConditionType { get; } + } + + /// + /// Specifies assertion type. If the assertion method argument satisfies the condition, + /// then the execution continues. Otherwise, execution is assumed to be halted. + /// + public enum AssertionConditionType + { + /// Marked parameter should be evaluated to true. + IS_TRUE = 0, + /// Marked parameter should be evaluated to false. + IS_FALSE = 1, + /// Marked parameter should be evaluated to null value. + IS_NULL = 2, + /// Marked parameter should be evaluated to not null value. + IS_NOT_NULL = 3 + } + + /// + /// Indicates that the marked method unconditionally terminates control flow execution. + /// For example, it could unconditionally throw exception. + /// + [Obsolete("Use [ContractAnnotation('=> halt')] instead")] + [AttributeUsage(AttributeTargets.Method)] + public sealed class TerminatesProgramAttribute : Attribute + { + } + + /// + /// Indicates that method is pure LINQ method, with postponed enumeration (like Enumerable.Select, + /// .Where). This annotation allows inference of [InstantHandle] annotation for parameters + /// of delegate type by analyzing LINQ method chains. + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class LinqTunnelAttribute : Attribute + { + } + + /// + /// Indicates that IEnumerable, passed as parameter, is not enumerated. + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class NoEnumerationAttribute : Attribute + { + } + + /// + /// Indicates that parameter is regular expression pattern. + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class RegexPatternAttribute : Attribute + { + } + + /// + /// Prevents the Member Reordering feature from tossing members of the marked class. + /// + /// + /// The attribute must be mentioned in your member reordering patterns + /// + [AttributeUsage( + AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.Enum)] + public sealed class NoReorderAttribute : Attribute + { + } + + /// + /// XAML attribute. Indicates the type that has ItemsSource property and should be treated + /// as ItemsControl-derived type, to enable inner items DataContext type resolve. + /// + [AttributeUsage(AttributeTargets.Class)] + public sealed class XamlItemsControlAttribute : Attribute + { + } + + /// + /// XAML attribute. Indicates the property of some BindingBase-derived type, that + /// is used to bind some item of ItemsControl-derived type. This annotation will + /// enable the DataContext type resolve for XAML bindings for such properties. + /// + /// + /// Property should have the tree ancestor of the ItemsControl type or + /// marked with the attribute. + /// + [AttributeUsage(AttributeTargets.Property)] + public sealed class XamlItemBindingOfItemsControlAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public sealed class AspChildControlTypeAttribute : Attribute + { + public AspChildControlTypeAttribute([NotNull] string tagName, [NotNull] Type controlType) + { + TagName = tagName; + ControlType = controlType; + } + + [NotNull] + public string TagName { get; } + + [NotNull] + public Type ControlType { get; } + } + + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] + public sealed class AspDataFieldAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] + public sealed class AspDataFieldsAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Property)] + public sealed class AspMethodPropertyAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public sealed class AspRequiredAttributeAttribute : Attribute + { + public AspRequiredAttributeAttribute([NotNull] string attribute) + { + Attribute = attribute; + } + + [NotNull] + public string Attribute { get; } + } + + [AttributeUsage(AttributeTargets.Property)] + public sealed class AspTypePropertyAttribute : Attribute + { + public AspTypePropertyAttribute(bool createConstructorReferences) + { + CreateConstructorReferences = createConstructorReferences; + } + + public bool CreateConstructorReferences { get; } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class RazorImportNamespaceAttribute : Attribute + { + public RazorImportNamespaceAttribute([NotNull] string name) + { + Name = name; + } + + [NotNull] + public string Name { get; } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class RazorInjectionAttribute : Attribute + { + public RazorInjectionAttribute([NotNull] string type, [NotNull] string fieldName) + { + Type = type; + FieldName = fieldName; + } + + [NotNull] + public string Type { get; } + + [NotNull] + public string FieldName { get; } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class RazorDirectiveAttribute : Attribute + { + public RazorDirectiveAttribute([NotNull] string directive) + { + Directive = directive; + } + + [NotNull] + public string Directive { get; } + } + + [AttributeUsage(AttributeTargets.Method)] + public sealed class RazorHelperCommonAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Property)] + public sealed class RazorLayoutAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Method)] + public sealed class RazorWriteLiteralMethodAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Method)] + public sealed class RazorWriteMethodAttribute : Attribute + { + } + + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class RazorWriteMethodParameterAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/QuickLook.Common/Properties/AssemblyInfo.cs b/QuickLook.Common/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..332eff8 --- /dev/null +++ b/QuickLook.Common/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("QuickLook.Common")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("QuickLook.Common")] +[assembly: AssemblyCopyright("Copyright © 2017-2026 QL-Win Contributors")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("85fdd6ba-871d-46c8-bd64-f6bb0cb5ea95")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] diff --git a/QuickLook.Common/QuickLook.Common.csproj b/QuickLook.Common/QuickLook.Common.csproj new file mode 100644 index 0000000..aa0b59d --- /dev/null +++ b/QuickLook.Common/QuickLook.Common.csproj @@ -0,0 +1,59 @@ + + + Library + net462 + QuickLook.Common + QuickLook.Common + AnyCPU;x64 + true + false + true + true + latest + false + {85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95} + + + + true + full + false + ..\Build\Debug\ + DEBUG;TRACE + 4 + + + + true + full + false + ..\Build\Debug\ + DEBUG;TRACE + 4 + + + + pdbonly + true + ..\Build\Release\ + TRACE + 4 + + + + pdbonly + true + ..\Build\Release\ + TRACE + 4 + + + + + + + + + powershell -ExecutionPolicy Bypass -file "$(SolutionDir)Scripts\update-version.ps1" + + diff --git a/QuickLook.Common/Styles/MainWindowStyles.Dark.xaml b/QuickLook.Common/Styles/MainWindowStyles.Dark.xaml new file mode 100644 index 0000000..ccc6054 --- /dev/null +++ b/QuickLook.Common/Styles/MainWindowStyles.Dark.xaml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/QuickLook.Common/Styles/MainWindowStyles.xaml b/QuickLook.Common/Styles/MainWindowStyles.xaml new file mode 100644 index 0000000..deee5d5 --- /dev/null +++ b/QuickLook.Common/Styles/MainWindowStyles.xaml @@ -0,0 +1,102 @@ + + 1 + 6 + 32 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/QuickLook.Common/Styles/ScrollBarStyleDictionary.xaml b/QuickLook.Common/Styles/ScrollBarStyleDictionary.xaml new file mode 100644 index 0000000..bd99989 --- /dev/null +++ b/QuickLook.Common/Styles/ScrollBarStyleDictionary.xaml @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file