├── .gitattributes ├── .gitignore ├── DBNewMotionFrames.mdf ├── DBNewMotionFrames_log.ldf ├── OnGuardCore.csproj ├── OnGuardCore.sln ├── OnGuardV2.csproj ├── README.md ├── Resources ├── HelpFiles │ ├── AddCameraHelp.rtf │ ├── CameraAddressHelp.rtf │ ├── CameraTriggeredHelp.rtf │ ├── DataFilesHelp.rtf │ ├── FolderPrefixHelp.rtf │ ├── ISpySnapshotHelp.rtf │ ├── MMSHelperHelp.rtf │ ├── ONVIFSnapshotHelp.rtf │ ├── OnGuardCaptureHelp.rtf │ ├── OnGuardMonitorHelp.rtf │ ├── PTZHelp.rtf │ ├── PTZMovementHelp.rtf │ ├── PresetsHelp.rtf │ ├── SnapshotMethodHelp.rtf │ └── SnapshotResolutionHelp.rtf ├── OnGuard.jpg ├── OnGuardNoPictures.jpg ├── Street1.jpg ├── Street2.jpg ├── Street3.jpg ├── Street4.jpg ├── Street5.jpg ├── Street6.jpg └── Street7.jpg ├── Setup └── Setup.vdproj ├── docs └── OnGuard-ReadMe.docx ├── obj └── Release │ └── net5.0-windows │ ├── Msix │ └── OnGuard.deps.json │ ├── OnGuardCore.ZoneBox.resources │ └── ref │ └── OnGuard.dll └── src ├── AI.cs ├── AIAnalyzer.cs ├── AIDetection.cs ├── AITimeUpdater.cs ├── AreaNotificationOption.cs ├── AreaOfInterest.cs ├── AreasOfInterestCollection.cs ├── AwaitableQueue.cs ├── BitmapResolution.cs ├── CameraCollection.cs ├── CameraContactData.cs ├── CameraData.cs ├── Controls ├── CameraImage.Designer.cs ├── CameraImage.cs ├── CameraImage.resx ├── EnhancedProgressBar.Designer.cs ├── EnhancedProgressBar.cs ├── EnhancedProgressBar.resx ├── Resizer.cs ├── Resizer.resx ├── TimeLine.Designer.cs ├── TimeLine.cs ├── TimeLine.resx ├── ZoneBox.cs └── ZoneBox.resx ├── Cooldowns.cs ├── DBConnection.cs ├── Dbg.cs ├── DirectoryMonitor.cs ├── EmailAccumulator.cs ├── EmailAddresses.cs ├── FaceDetection.cs ├── Forms ├── AIAlertDialog.Designer.cs ├── AIAlertDialog.cs ├── AIAlertDialog.resx ├── AboutDialog.Designer.cs ├── AboutDialog.cs ├── AboutDialog.resx ├── AddCameraDialog.Designer.cs ├── AddCameraDialog.cs ├── AddCameraDialog.resx ├── AddEmailDialog.Designer.cs ├── AddEmailDialog.cs ├── AddEmailDialog.resx ├── AddFaceDialog.Designer.cs ├── AddFaceDialog.cs ├── AddFaceDialog.resx ├── AddUrlDialog.Designer.cs ├── AddUrlDialog.cs ├── AddUrlDialog.resx ├── AnalysisSettingsDialog.Designer.cs ├── AnalysisSettingsDialog.cs ├── AnalysisSettingsDialog.resx ├── AutoFindCamera.Designer.cs ├── AutoFindCamera.cs ├── AutoFindCamera.resx ├── BlueIrisSnapshot.Designer.cs ├── BlueIrisSnapshot.cs ├── BlueIrisSnapshot.resx ├── CameraConfigurationDialog.Designer.cs ├── CameraConfigurationDialog.cs ├── CameraConfigurationDialog.resx ├── CleanupDialog.Designer.cs ├── CleanupDialog.cs ├── CleanupDialog.resx ├── CreateAOI.Designer.cs ├── CreateAOI.cs ├── CreateAOI.resx ├── CreateEmailAddressDialog.Designer.cs ├── CreateEmailAddressDialog.cs ├── CreateEmailAddressDialog.resx ├── DisplayMode.Designer.cs ├── DisplayMode.cs ├── DisplayMode.resx ├── EditAreasOfInterest.Designer.cs ├── EditAreasOfInterest.cs ├── EditAreasOfInterest.resx ├── EmailAddressesDialog.Designer.cs ├── EmailAddressesDialog.cs ├── EmailAddressesDialog.resx ├── FaceDefinitionDialog.Designer.cs ├── FaceDefinitionDialog.cs ├── FaceDefinitionDialog.resx ├── FaceName.Designer.cs ├── FaceName.cs ├── FaceName.resx ├── HTTPPresets.Designer.cs ├── HTTPPresets.cs ├── HTTPPresets.resx ├── HTTPptz.Designer.cs ├── HTTPptz.cs ├── HTTPptz.resx ├── HelpBox.Designer.cs ├── HelpBox.cs ├── HelpBox.resx ├── HttpSnapshot.Designer.cs ├── HttpSnapshot.cs ├── HttpSnapshot.resx ├── ISpyPTZ.Designer.cs ├── ISpyPTZ.cs ├── ISpyPTZ.resx ├── ISpySnapshot.Designer.cs ├── ISpySnapshot.cs ├── ISpySnapshot.resx ├── ImageCaptureDialog.Designer.cs ├── ImageCaptureDialog.cs ├── ImageCaptureDialog.resx ├── InitialPictureBehaviorDialog.Designer.cs ├── InitialPictureBehaviorDialog.cs ├── InitialPictureBehaviorDialog.resx ├── InterestingItemsDialog.Designer.cs ├── InterestingItemsDialog.cs ├── InterestingItemsDialog.resx ├── MMS-Helper.Designer.cs ├── MMS-Helper.cs ├── MMS-Helper.resx ├── MQTTSettings.Designer.cs ├── MQTTSettings.cs ├── MQTTSettings.resx ├── MainWindow.Designer.cs ├── MainWindow.cs ├── MainWindow.resx ├── ModelessMessageWindow.Designer.cs ├── ModelessMessageWindow.cs ├── ModelessMessageWindow.resx ├── NotificationOptionsDialog.Designer.cs ├── NotificationOptionsDialog.cs ├── NotificationOptionsDialog.resx ├── ObjectDefinitionDialog.Designer.cs ├── ObjectDefinitionDialog.cs ├── ObjectDefinitionDialog.resx ├── OnGuardDataDialog.Designer.cs ├── OnGuardDataDialog.cs ├── OnGuardDataDialog.resx ├── OnVIFSnapshot.Designer.cs ├── OnVIFSnapshot.cs ├── OnVIFSnapshot.resx ├── OutgoingEmailDialog.Designer.cs ├── OutgoingEmailDialog.cs ├── OutgoingEmailDialog.resx ├── PTZMovement.Designer.cs ├── PTZMovement.cs ├── PTZMovement.resx ├── PictureDateSelect.Designer.cs ├── PictureDateSelect.cs ├── PictureDateSelect.resx ├── ScheduledPreset.Designer.cs ├── ScheduledPreset.cs ├── ScheduledPreset.resx ├── SetLogLevelDialog.Designer.cs ├── SetLogLevelDialog.cs ├── SetLogLevelDialog.resx ├── SettingsDialog.Designer.cs ├── SettingsDialog.cs ├── SettingsDialog.resx ├── StartRestartAI.Designer.cs ├── StartRestartAI.cs ├── StartRestartAI.resx ├── SyncToDatabaseDialog.Designer.cs ├── SyncToDatabaseDialog.cs ├── SyncToDatabaseDialog.resx ├── Test Email Address.Designer.cs ├── Test Email Address.cs ├── Test Email Address.resx ├── TestPIcturesDialog.Designer.cs ├── TestPIcturesDialog.cs ├── TestPIcturesDialog.resx ├── TestPresets.Designer.cs ├── TestPresets.cs ├── TestPresets.resx ├── iSpyPreset.Designer.cs ├── iSpyPreset.cs └── iSpyPreset.resx ├── FrameAccumulator.cs ├── FrameAnalyzer.cs ├── GlobalData.cs ├── GlobalSuppressions.cs ├── GridDefinition.cs ├── History.cs ├── IStorage.cs ├── ImageObject.cs ├── MQTTPublish.cs ├── MostRecentCollection.cs ├── MotionDatabase.cs ├── ObjectCharacteristics.cs ├── OnGuardScanner.cs ├── OnVIFSupport.cs ├── PendingItem.cs ├── Picture.cs ├── PictureComparer.cs ├── PictureInfo.cs ├── PictureMotionInfo.cs ├── Program.cs ├── Properties ├── Resource.Designer.cs ├── Resource.resx ├── SamplePictureResources.Designer.cs ├── SamplePictureResources.resx ├── Settings.Designer.cs └── Settings.settings ├── Resources ├── Icons │ ├── Guardian.ico │ ├── arrow-down.png │ ├── arrow-left.png │ ├── arrow-right.png │ ├── arrow-up.png │ ├── zoom-in.png │ └── zoom-out.png ├── Images │ ├── OnGuard.jpg │ └── OnGuardNoPictures.jpg └── Samples │ ├── Street1.jpg │ ├── Street2.jpg │ ├── Street3.jpg │ ├── Street4.jpg │ ├── Street5.jpg │ ├── Street6.jpg │ └── Street7.jpg ├── SafeParse.cs ├── Storage.cs ├── SyncToDB.cs ├── TimeTrigger.cs ├── TimerPlus.cs ├── TriggerCamera.cs ├── WaitCursor.cs └── XMLStorage.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * -crlf 5 | * -text 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /DBNewMotionFrames.mdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/DBNewMotionFrames.mdf -------------------------------------------------------------------------------- /DBNewMotionFrames_log.ldf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/DBNewMotionFrames_log.ldf -------------------------------------------------------------------------------- /OnGuardCore.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OnGuardCore", "OnGuardCore.csproj", "{927CF148-F6BB-41EC-BB98-BF61D8CADBF3}" 7 | EndProject 8 | Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "Setup", "Setup\Setup.vdproj", "{006F4EC1-F5CF-4442-B9D2-807F48303511}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|x64 = Debug|x64 14 | Release|Any CPU = Release|Any CPU 15 | Release|x64 = Release|x64 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {927CF148-F6BB-41EC-BB98-BF61D8CADBF3}.Debug|Any CPU.ActiveCfg = Debug|x64 19 | {927CF148-F6BB-41EC-BB98-BF61D8CADBF3}.Debug|Any CPU.Build.0 = Debug|x64 20 | {927CF148-F6BB-41EC-BB98-BF61D8CADBF3}.Debug|x64.ActiveCfg = Debug|x64 21 | {927CF148-F6BB-41EC-BB98-BF61D8CADBF3}.Debug|x64.Build.0 = Debug|x64 22 | {927CF148-F6BB-41EC-BB98-BF61D8CADBF3}.Release|Any CPU.ActiveCfg = Release|x64 23 | {927CF148-F6BB-41EC-BB98-BF61D8CADBF3}.Release|Any CPU.Build.0 = Release|x64 24 | {927CF148-F6BB-41EC-BB98-BF61D8CADBF3}.Release|x64.ActiveCfg = Release|x64 25 | {927CF148-F6BB-41EC-BB98-BF61D8CADBF3}.Release|x64.Build.0 = Release|x64 26 | {006F4EC1-F5CF-4442-B9D2-807F48303511}.Debug|Any CPU.ActiveCfg = Release 27 | {006F4EC1-F5CF-4442-B9D2-807F48303511}.Debug|x64.ActiveCfg = Debug 28 | {006F4EC1-F5CF-4442-B9D2-807F48303511}.Release|Any CPU.ActiveCfg = Release 29 | {006F4EC1-F5CF-4442-B9D2-807F48303511}.Release|Any CPU.Build.0 = Release 30 | {006F4EC1-F5CF-4442-B9D2-807F48303511}.Release|x64.ActiveCfg = Release 31 | {006F4EC1-F5CF-4442-B9D2-807F48303511}.Release|x64.Build.0 = Release 32 | EndGlobalSection 33 | GlobalSection(SolutionProperties) = preSolution 34 | HideSolutionNode = FALSE 35 | EndGlobalSection 36 | GlobalSection(ExtensibilityGlobals) = postSolution 37 | SolutionGuid = {787AB3AB-A171-4077-9BAF-6F286EC75237} 38 | EndGlobalSection 39 | EndGlobal 40 | -------------------------------------------------------------------------------- /OnGuardV2.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net5.0-windows 6 | true 7 | 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This application works with almost any IP/network camera and adds artificial intelligence designed to identify security related pictures. More specifically, it uses DeepStack as an AI to intelligently identify objects in still (.jpg) pictures. It allows the user to monitor as many cameras as desired. It allows the user to visually create multiple areas that are of security interest, including the types of objects that are of interest in each area. 2 | 3 | Version 3.0.1 is a significant update to previous versions. The most dramatic difference is that it fully supports any known camera that supports ONVIF or HTTP. On Guard can now obtain and analyze pictures from (1) the camera itself without disk storage (2) messages sent by a camera using FTP, and taking advantage of motion sensing capabilities of the camera (3) Blue Iris or other applications that write motion related still images to disk. 4 | 5 | On Guard 3.0 features 6 | 7 | It is provided free of charge. 8 | ONVIF and HTTP based cameras are fully supported. This should include almost any camera not locked into a manufacturer proprietary system. 9 | Is fully compatible with, but not reliant on Blue Iris. 10 | Supports multiple cameras. 11 | Support for cameras with different resolution and cameras from different manufacturers. 12 | You can design areas of interest (zones) to identify or ignore activity in an area, including overlapping areas. 13 | You can design your areas to be in almost any shape desired (a 64x64 grid on the pictures). 14 | You can choose to base security notifications based on the size of identified objects (how big and how close they are to the camera). 15 | Supports facial recognition. 16 | Optionally manage the start/stop/reset of the DeepStack AI. 17 | Notify any application that can take an action as a result of an HTTP message/request. 18 | Supports IFTTT activation of lights and other smart devices. 19 | Supports MQTT. 20 | Supports email notification of clients with attached pictures. This also includes the ability to send MMS/SMS messages to phones that support it. 21 | Supports Pan/Tilt/Zoom, and move to preset for cameras that support these features. 22 | Tracks pictures with identified items of interest in a database so that you can move only through those pictures if desired. 23 | Provides a timeline scroll bar. You can now use a track bar to scroll to pictures at any desired date/time. 24 | Cleanup old/uninteresting pictures for one or all cameras. 25 | Detailed documentation/instructions are included. 26 | Can display snapshot pictures/video as an aid in defining areas of interest and camera positioning. 27 | 28 | Features Not Supported 29 | 30 | Does NOT store video to disk. 31 | Does NOT playback videos. 32 | While you can play live video (motion .jpg) directly from a camera, this capability is limited (and not smooth). 33 | Does not support many doorbell cameras, and cameras locked into a proprietary camera ecosystem. 34 | -------------------------------------------------------------------------------- /Resources/OnGuard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/Resources/OnGuard.jpg -------------------------------------------------------------------------------- /Resources/OnGuardNoPictures.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/Resources/OnGuardNoPictures.jpg -------------------------------------------------------------------------------- /Resources/Street1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/Resources/Street1.jpg -------------------------------------------------------------------------------- /Resources/Street2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/Resources/Street2.jpg -------------------------------------------------------------------------------- /Resources/Street3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/Resources/Street3.jpg -------------------------------------------------------------------------------- /Resources/Street4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/Resources/Street4.jpg -------------------------------------------------------------------------------- /Resources/Street5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/Resources/Street5.jpg -------------------------------------------------------------------------------- /Resources/Street6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/Resources/Street6.jpg -------------------------------------------------------------------------------- /Resources/Street7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/Resources/Street7.jpg -------------------------------------------------------------------------------- /docs/OnGuard-ReadMe.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/docs/OnGuard-ReadMe.docx -------------------------------------------------------------------------------- /obj/Release/net5.0-windows/OnGuardCore.ZoneBox.resources: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/obj/Release/net5.0-windows/OnGuardCore.ZoneBox.resources -------------------------------------------------------------------------------- /obj/Release/net5.0-windows/ref/OnGuard.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/obj/Release/net5.0-windows/ref/OnGuard.dll -------------------------------------------------------------------------------- /src/AITimeUpdater.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace OnGuardCore 8 | { 9 | public static class AITimeUpdater 10 | { 11 | public delegate void AIProcessTimeDelegate(TimeSpan timespan); 12 | public static event AIProcessTimeDelegate OnAITimeUpdate = delegate {}; 13 | public static event AIProcessTimeDelegate OnFrameTimeUpdate = delegate { }; 14 | 15 | public static void UpdateFrameTime(TimeSpan span) 16 | { 17 | OnFrameTimeUpdate(span); 18 | } 19 | 20 | public static void UpdateAITime(TimeSpan span) 21 | { 22 | OnAITimeUpdate(span); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/AwaitableQueue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Runtime.CompilerServices; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using Microsoft.VisualStudio.Threading; 9 | 10 | namespace OnGuardCore 11 | { 12 | 13 | public class AwaitableQueue : IDisposable 14 | { 15 | int _waitTime; 16 | bool _stop; 17 | 18 | ConcurrentQueue _q = new (); 19 | AsyncAutoResetEvent _available = new (true); 20 | private bool disposedValue; 21 | 22 | public AwaitableQueue(int waitTimeInSeconds) 23 | { 24 | _waitTime = waitTimeInSeconds; // 0 - no timeout 25 | } 26 | 27 | public void Add(T addIt) 28 | { 29 | _q.Enqueue(addIt); 30 | _available.Set(); 31 | } 32 | 33 | public async Task GetAsync() 34 | { 35 | T result = default; 36 | 37 | while (!_stop) 38 | { 39 | if (_q.TryDequeue(out result)) 40 | { 41 | break; 42 | } 43 | else 44 | { 45 | CancellationTokenSource source = new (); 46 | if (_waitTime > 0) 47 | { 48 | source.CancelAfter(_waitTime * 1000); 49 | } 50 | 51 | DateTime startAIWaitTime = DateTime.Now; 52 | 53 | CancellationToken token = source.Token; 54 | await _available.WaitAsync(token).ConfigureAwait(true); 55 | if (token.IsCancellationRequested) 56 | { 57 | TimeSpan span = DateTime.Now - startAIWaitTime; 58 | Dbg.Write(LogLevel.Warning, "AIDetection - Timeout trying to get an AI instance with time: " + span.TotalSeconds.ToString()); 59 | break; 60 | } 61 | } 62 | } 63 | 64 | return result; 65 | } 66 | 67 | protected virtual void Dispose(bool disposing) 68 | { 69 | if (!disposedValue) 70 | { 71 | if (disposing) 72 | { 73 | _stop = true; 74 | _available.Set(); 75 | } 76 | disposedValue = true; 77 | } 78 | } 79 | 80 | public void Dispose() 81 | { 82 | // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method 83 | Dispose(disposing: true); 84 | GC.SuppressFinalize(this); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/BitmapResolution.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace OnGuardCore 10 | { 11 | 12 | /// 13 | /// Just a class to hold a global that has the resolution of the source bitmap 14 | /// We need to access it from multiple files. 15 | /// 16 | public static class BitmapResolution 17 | { 18 | static public int XResolution { get; set; } = 1024; 19 | static public int YResolution { get; set; } = 768; 20 | static public double XScale { get; set; } = 1.0; 21 | static public double YScale { get; set; } = 1.0; 22 | 23 | public static Rectangle ScaleScreenToData(Rectangle rect) 24 | { 25 | Rectangle result = new Rectangle((int)Math.Round(rect.X * XScale), (int)Math.Round(rect.Y * YScale), (int)Math.Round(rect.Width * XScale), (int)Math.Round(rect.Height * YScale)); 26 | return result; 27 | } 28 | 29 | public static Point ScaleScreenToData(Point point) 30 | { 31 | Point result = new Point((int)Math.Round(point.X * XScale), (int)Math.Round(point.Y * YScale)); 32 | return result; 33 | } 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/Controls/CameraImage.Designer.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace OnGuardCore 3 | { 4 | partial class CameraImage 5 | { 6 | /// 7 | /// Required designer variable. 8 | /// 9 | private System.ComponentModel.IContainer components = null; 10 | 11 | /// 12 | /// Clean up any resources being used. 13 | /// 14 | /// true if managed resources should be disposed; otherwise, false. 15 | protected override void Dispose(bool disposing) 16 | { 17 | if (disposing && (components != null)) 18 | { 19 | components.Dispose(); 20 | } 21 | base.Dispose(disposing); 22 | } 23 | 24 | #region Component Designer generated code 25 | 26 | /// 27 | /// Required method for Designer support - do not modify 28 | /// the contents of this method with the code editor. 29 | /// 30 | private void InitializeComponent() 31 | { 32 | components = new System.ComponentModel.Container(); 33 | } 34 | 35 | #endregion 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Controls/CameraImage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Threading; 10 | using System.Windows.Forms; 11 | 12 | namespace OnGuardCore 13 | { 14 | public partial class CameraImage : PictureBox 15 | { 16 | private object _lock = new object(); 17 | 18 | internal int WS_EX_TRANSPARENT = 0x00000020; 19 | Color _color = Color.FromArgb(80, Color.DarkOrange); 20 | 21 | private List _grids; 22 | public CameraImage() 23 | { 24 | InitializeComponent(); 25 | } 26 | 27 | public void SetImage(Bitmap bitmap) 28 | { 29 | Bitmap oldBitmap = (Bitmap)Image; // can't dispose until we have set the new one 30 | this.Image = new Bitmap(bitmap); 31 | oldBitmap?.Dispose(); 32 | } 33 | 34 | public List GridsSelected 35 | { 36 | get 37 | { 38 | lock (_lock) 39 | { 40 | return _grids; 41 | } 42 | } 43 | set 44 | { 45 | lock (_lock) 46 | { 47 | _grids = value; 48 | } 49 | } 50 | } 51 | 52 | 53 | protected override void OnPaint(PaintEventArgs pe) 54 | { 55 | try 56 | { 57 | 58 | // _semaphore.Wait(); 59 | base.OnPaint(pe); 60 | 61 | if (GridsSelected != null && GridsSelected.Count > 0) 62 | { 63 | double xSpan = (double) this.Width / (double)GridsSelected[0].XDim; 64 | double ySpan = (double) this.Height / (double) GridsSelected[0].YDim; 65 | 66 | using (SolidBrush brush = new SolidBrush(_color)) 67 | { 68 | foreach (var grid in GridsSelected) 69 | { 70 | for (int row = 0; row < grid.YDim; row++) 71 | { 72 | for (int col = 0; col < grid.XDim; col++) 73 | { 74 | if (grid.Get(col, row)) 75 | { 76 | pe.Graphics.FillRectangle(brush, (int) Math.Round(col * xSpan), (int) Math.Round(row * ySpan), (int) xSpan + 1, (int) ySpan + 1); 77 | } 78 | } 79 | } 80 | } 81 | } 82 | } 83 | } 84 | finally 85 | { 86 | //_semaphore.Release(); 87 | } 88 | } 89 | 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/Controls/EnhancedProgressBar.Designer.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace OnGuardCore 3 | { 4 | partial class EnhancedProgressBar 5 | { 6 | /// 7 | /// Required designer variable. 8 | /// 9 | private System.ComponentModel.IContainer components = null; 10 | 11 | /// 12 | /// Clean up any resources being used. 13 | /// 14 | /// true if managed resources should be disposed; otherwise, false. 15 | protected override void Dispose(bool disposing) 16 | { 17 | if (disposing && (components != null)) 18 | { 19 | components.Dispose(); 20 | } 21 | base.Dispose(disposing); 22 | } 23 | 24 | #region Component Designer generated code 25 | 26 | /// 27 | /// Required method for Designer support - do not modify 28 | /// the contents of this method with the code editor. 29 | /// 30 | private void InitializeComponent() 31 | { 32 | this.SuspendLayout(); 33 | // 34 | // UserControl1 35 | // 36 | this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); 37 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; 38 | this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 39 | this.Name = "UserControl1"; 40 | this.Size = new System.Drawing.Size(187, 22); 41 | this.ResumeLayout(false); 42 | 43 | } 44 | 45 | #endregion 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Controls/EnhancedProgressBar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Drawing.Drawing2D; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Windows.Forms; 11 | 12 | namespace OnGuardCore 13 | { 14 | public partial class EnhancedProgressBar : UserControl 15 | { 16 | SolidBrush eraseBrush; 17 | public EnhancedProgressBar() 18 | { 19 | InitializeComponent(); 20 | eraseBrush = new SolidBrush(this.BackColor); 21 | 22 | } 23 | 24 | public void SetContents(Color color, double percent, string text) 25 | { 26 | using (Graphics g = this.CreateGraphics()) 27 | { 28 | Rectangle clientRect = this.ClientRectangle; 29 | g.FillRectangle(eraseBrush, clientRect); 30 | 31 | using (SolidBrush barBrush = new SolidBrush(color)) 32 | { 33 | Rectangle barRect = clientRect; 34 | barRect.Width = (int)((double)clientRect.Width * percent / 100.0); 35 | g.FillRectangle(barBrush, barRect); 36 | 37 | g.SmoothingMode = SmoothingMode.AntiAlias; 38 | g.InterpolationMode = InterpolationMode.HighQualityBicubic; 39 | g.PixelOffsetMode = PixelOffsetMode.HighQuality; 40 | 41 | using (Font f = new Font("Tahoma", 8, FontStyle.Bold)) 42 | { 43 | SizeF stringWidth = g.MeasureString(text, f); 44 | int left = clientRect.Width / 2 - (int) stringWidth.Width / 2; 45 | Rectangle textRect = clientRect; 46 | textRect.X = left; 47 | g.DrawString(text, f, Brushes.Black, textRect); 48 | } 49 | } 50 | 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Controls/TimeLine.Designer.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.Windows.Forms; 3 | 4 | namespace OnGuardCore 5 | { 6 | partial class TimeLine : TrackBar 7 | { 8 | /// 9 | /// Required designer variable. 10 | /// 11 | private System.ComponentModel.IContainer components = null; 12 | 13 | /// 14 | /// Clean up any resources being used. 15 | /// 16 | /// true if managed resources should be disposed; otherwise, false. 17 | protected override void Dispose(bool disposing) 18 | { 19 | if (disposing && (components != null)) 20 | { 21 | components.Dispose(); 22 | } 23 | base.Dispose(disposing); 24 | } 25 | 26 | #region Component Designer generated code 27 | 28 | /// 29 | /// Required method for Designer support - do not modify 30 | /// the contents of this method with the code editor. 31 | /// 32 | private void InitializeComponent() 33 | { 34 | components = new System.ComponentModel.Container(); 35 | } 36 | 37 | #endregion 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Controls/ZoneBox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | 5 | namespace OnGuardCore 6 | { 7 | 8 | public class ZoneBox : Panel 9 | { 10 | internal int WS_EX_TRANSPARENT = 0x00000020; 11 | Color _color; 12 | readonly Color _focusColor = Color.FromArgb(200, Color.MediumAquamarine); 13 | Rectangle _focusRect = Rectangle.Empty; 14 | Point _focusPoint = Point.Empty; 15 | 16 | public Point ZoneFocus 17 | { 18 | get 19 | { 20 | return _focusPoint; 21 | } 22 | set 23 | { 24 | _focusPoint = value; 25 | _focusRect = new Rectangle(ZoneFocus.X - 5, ZoneFocus.Y - 5, 10, 10); 26 | } 27 | } 28 | 29 | public ZoneBox(Color color) : base() 30 | { 31 | _color = color; 32 | 33 | InitializeComponent(); 34 | this.SetStyle(ControlStyles.Opaque | 35 | ControlStyles.ResizeRedraw | 36 | ControlStyles.SupportsTransparentBackColor, true); 37 | this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false); 38 | this.BorderStyle = BorderStyle.None; 39 | 40 | BringToFront(); 41 | } 42 | 43 | protected override CreateParams CreateParams 44 | { 45 | get 46 | { 47 | CreateParams parameters = base.CreateParams; 48 | parameters.ExStyle |= WS_EX_TRANSPARENT; 49 | return parameters; 50 | } 51 | } 52 | 53 | protected override void OnLocationChanged(EventArgs e) 54 | { 55 | Parent.Invalidate(); 56 | Invalidate(); 57 | } 58 | 59 | protected override void OnPaint(PaintEventArgs e) 60 | { 61 | //base.OnPaint(e); 62 | e.Graphics.SetClip(new Rectangle(0, 0, Width, Height)); 63 | using (SolidBrush brush = new SolidBrush(_color)) 64 | { 65 | e.Graphics.FillRectangle(brush, 0, 0, this.Width + 1, this.Height + 1); 66 | if (_focusRect != Rectangle.Empty) 67 | { 68 | using (SolidBrush focusBrush = new SolidBrush(_focusColor)) 69 | { 70 | e.Graphics.FillRectangle(focusBrush, _focusRect); 71 | } 72 | } 73 | } 74 | } 75 | 76 | protected override void OnPaintBackground(PaintEventArgs e) 77 | { 78 | e.Graphics.SetClip(new Rectangle(0, 0, Width, Height)); 79 | using (SolidBrush brush = new SolidBrush(_color)) 80 | { 81 | e.Graphics.FillRectangle(brush, 0, 0, this.Width + 1, this.Height + 1); 82 | } 83 | } 84 | 85 | private void InitializeComponent() 86 | { 87 | this.SuspendLayout(); 88 | // 89 | // ZoneBox 90 | // 91 | this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.OnMouseDown); 92 | this.ResumeLayout(false); 93 | 94 | } 95 | 96 | private void OnMouseDown(object sender, MouseEventArgs e) 97 | { 98 | if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift) 99 | { 100 | _focusRect = BitmapResolution.ScaleScreenToData(new Rectangle(e.X - 5, e.Y - 5, 10, 10)); 101 | ZoneFocus = e.Location; 102 | } 103 | 104 | Parent.Invalidate(); 105 | this.Invalidate(); 106 | } 107 | 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/DBConnection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using OnGuardCore.Src.Properties; 8 | 9 | namespace OnGuardCore 10 | { 11 | public static class DBConnection 12 | { 13 | /// 14 | /// Get either the custom connection string or the default one. 15 | /// 16 | /// 17 | public static string GetConnectionString() 18 | { 19 | string connectionString = string.Empty; 20 | connectionString = Storage.Instance.GetGlobalString("CustomDatabaseConnectionString"); 21 | 22 | if (string.IsNullOrEmpty(connectionString)) 23 | { 24 | // This the normal case where there is no custom string 25 | connectionString = GetDefaultConnectionString(); 26 | 27 | /* 28 | string currentString = Storage.Instance.GetGlobalString("DBConnectionString"); 29 | connectionString = GetDefaultConnectionString(); 30 | if (currentString != connectionString) 31 | { 32 | Dbg.Write("DBConnection - GetConnectionString - Unexpected location difference"); 33 | Storage.Instance.SetGlobalString("DBConnectionString", connectionString); 34 | Storage.Instance.Update(); 35 | } 36 | */ 37 | } 38 | 39 | return connectionString; 40 | } 41 | 42 | /// 43 | /// Store the path (only) to the database 44 | /// 45 | /// 46 | public static void SetDatabasePath(string path) 47 | { 48 | Storage.Instance.SetGlobalString("DatabasePath", path); 49 | Storage.Instance.Update(); 50 | } 51 | 52 | public static string GetDatabasePath() 53 | { 54 | string path = Storage.Instance.GetGlobalString("DatabasePath"); 55 | if (string.IsNullOrEmpty(path)) 56 | { 57 | path = Settings.Default.DataFileLocation; 58 | Storage.Instance.SetGlobalInt("DBLocationType", 0); // the user directory 59 | } 60 | 61 | return path; 62 | } 63 | 64 | /// 65 | /// The settings connection string is the minimal connection string without a path. Instead it has a {0] for the path that is then filled in here. 66 | /// If we have already set the database path in the xml file we use that. Otherwise we use the user directory where the installer should have 67 | /// put the database. 68 | /// No luck using |DataDirectory 69 | /// 70 | /// 71 | public static string GetDefaultConnectionString() 72 | { 73 | // Since we are getting the value we need to format it 74 | string baseConnectionString = Settings.Default.DBMotionFramesConnectionString; // the base string with {0} in place of the file location 75 | string dbLocation = GetDatabasePath(); 76 | string connectionString = string.Format(baseConnectionString, dbLocation); // insert the localdb path 77 | return connectionString; 78 | } 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/EmailAddresses.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.Serialization.Formatters.Binary; 5 | 6 | namespace OnGuardCore 7 | { 8 | /// 9 | /// Just a wrapper that holds a list of the available email addresses (along with the related time/dow restrictions 10 | /// Provides a wrapper for persistence. 11 | /// 12 | [Serializable] 13 | public sealed class EmailAddresses 14 | { 15 | 16 | public static List EmailAddressList { get; set; } 17 | 18 | static EmailAddresses() 19 | { 20 | EmailAddressList = new List(); 21 | Load(); 22 | } 23 | 24 | static public EmailOptions GetEmailOptions(string emailAddress) 25 | { 26 | EmailOptions opt = null; 27 | opt = EmailAddressList.Find(x => emailAddress == x.EmailAddress); 28 | return opt; 29 | } 30 | 31 | public static void Save() 32 | { 33 | Storage.Instance.SaveEmailAddresses(EmailAddressList); 34 | } 35 | 36 | public static void Load() 37 | { 38 | EmailAddressList = Storage.Instance.GetEmailAddresses(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Forms/AIAlertDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace OnGuardCore 12 | { 13 | public partial class AIAlertDialog : Form 14 | { 15 | public AIAlertDialog() 16 | { 17 | InitializeComponent(); 18 | foreach (var options in EmailAddresses.EmailAddressList) 19 | { 20 | EmailListBox.Items.Add(options.EmailAddress); 21 | } 22 | 23 | string emailRecipient = Storage.Instance.GetGlobalString("NotifyAIGoneEmail"); 24 | 25 | if (!string.IsNullOrEmpty(emailRecipient)) 26 | { 27 | EmailListBox.SelectedItem = emailRecipient; 28 | } 29 | 30 | string mqttAIDiedTopic = Storage.Instance.GetGlobalString("MQTTaiDiedTopic"); 31 | string mqttAIDiedPayload = Storage.Instance.GetGlobalString("MQTTaiDiedPayload"); 32 | bool mqttSendAIDied = Storage.Instance.GetGlobalBool("MQTTSendAIDied"); 33 | 34 | if (!string.IsNullOrEmpty(mqttAIDiedTopic)) 35 | { 36 | AIDiedTopicText.Text = mqttAIDiedTopic; 37 | } 38 | 39 | if (!string.IsNullOrEmpty(mqttAIDiedPayload)) 40 | { 41 | AIDiedPayloadText.Text = mqttAIDiedPayload; 42 | } 43 | 44 | sendAIDiedMQTTCheckbox.Checked = mqttSendAIDied; 45 | 46 | } 47 | 48 | private void OKButton_Click(object sender, EventArgs e) 49 | { 50 | if (EmailListBox.SelectedItems.Count > 0) 51 | { 52 | Storage.Instance.SetGlobalString("NotifyAIGoneEmail", (string)EmailListBox.SelectedItem); 53 | } 54 | 55 | Storage.Instance.SetGlobalString("MQTTaiDiedTopic", AIDiedTopicText.Text); 56 | Storage.Instance.SetGlobalString("MQTTaiDiedPayload", AIDiedPayloadText.Text); 57 | Storage.Instance.SetGlobalBool("MQTTSendAIDied", sendAIDiedMQTTCheckbox.Checked); 58 | Storage.Instance.Update(); 59 | DialogResult = DialogResult.OK; 60 | } 61 | 62 | private void CancelButton_Click(object sender, EventArgs e) 63 | { 64 | DialogResult = DialogResult.Cancel; 65 | } 66 | 67 | private void RemoveButton_Click(object sender, EventArgs e) 68 | { 69 | EmailListBox.SelectedIndex = -1; 70 | Storage.Instance.RemoveGlobalValue("NotifyAIGoneEmail"); 71 | } 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /src/Forms/AIAlertDialog.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | 61 | When/if your AI server dies OR IS VERY SLOW TO RESPOND (overloaded) you may receive a notification via email and/or MQTT. At the moment this notification is limited to one (and only one) email address. 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/Forms/AboutDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Security.Cryptography.X509Certificates; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Windows.Forms; 11 | using System.Reflection; 12 | 13 | 14 | namespace OnGuardCore 15 | { 16 | public partial class AboutDialog : Form 17 | { 18 | public AboutDialog() 19 | { 20 | InitializeComponent(); 21 | assemblyLabel.Text = AssemblyVersion; 22 | } 23 | 24 | public static string AssemblyTitle 25 | { 26 | get 27 | { 28 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); 29 | if (attributes.Length > 0) 30 | { 31 | AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0]; 32 | if (!string.IsNullOrEmpty(titleAttribute.Title)) 33 | { 34 | return titleAttribute.Title; 35 | } 36 | } 37 | return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); 38 | } 39 | } 40 | 41 | public static string AssemblyVersion 42 | { 43 | get 44 | { 45 | return Assembly.GetExecutingAssembly().GetName().Version.ToString(); 46 | } 47 | } 48 | 49 | public static string AssemblyDescription 50 | { 51 | get 52 | { 53 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); 54 | if (attributes.Length == 0) 55 | { 56 | return ""; 57 | } 58 | return ((AssemblyDescriptionAttribute)attributes[0]).Description; 59 | } 60 | } 61 | 62 | public static string AssemblyProduct 63 | { 64 | get 65 | { 66 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); 67 | if (attributes.Length == 0) 68 | { 69 | return ""; 70 | } 71 | return ((AssemblyProductAttribute)attributes[0]).Product; 72 | } 73 | } 74 | 75 | public static string AssemblyCopyright 76 | { 77 | get 78 | { 79 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); 80 | if (attributes.Length == 0) 81 | { 82 | return ""; 83 | } 84 | return ((AssemblyCopyrightAttribute)attributes[0]).Copyright; 85 | } 86 | } 87 | 88 | public static string AssemblyCompany 89 | { 90 | get 91 | { 92 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); 93 | if (attributes.Length == 0) 94 | { 95 | return ""; 96 | } 97 | return ((AssemblyCompanyAttribute)attributes[0]).Company; 98 | } 99 | } 100 | 101 | private void OKButton_Click(object sender, EventArgs e) 102 | { 103 | DialogResult = DialogResult.OK; 104 | } 105 | } 106 | 107 | 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/Forms/AddCameraDialog.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | 61 | All image generation methods require that you specify the prefix for picture image names. The remainder on the name must be unique to the individual picture. 62 | 63 | An example is: “aiFrontCamera2012_09_13_4234565.jpg” 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/Forms/AddEmailDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace OnGuardCore 5 | { 6 | 7 | /// 8 | /// A simple dialog to add email addresses to the AOI notifications dialog 9 | /// 10 | public partial class AddEmailDialog : Form 11 | { 12 | public string EmailAddress { get; set; } 13 | public AddEmailDialog() 14 | { 15 | InitializeComponent(); 16 | foreach (var options in EmailAddresses.EmailAddressList) 17 | { 18 | emailAddressList.Items.Add(options.EmailAddress); 19 | } 20 | } 21 | 22 | private void OkButton_Click(object sender, EventArgs e) 23 | { 24 | if (null != emailAddressList.SelectedItem) 25 | { 26 | EmailAddress = (string)emailAddressList.SelectedItem; 27 | DialogResult = DialogResult.OK; 28 | } 29 | else 30 | { 31 | MessageBox.Show("You must select an email address or press Cancel"); 32 | } 33 | } 34 | 35 | private void CancelButton_Click(object sender, EventArgs e) 36 | { 37 | DialogResult = DialogResult.Cancel; 38 | } 39 | 40 | private void OnMouseDoubleClick(object sender, MouseEventArgs e) 41 | { 42 | if (null != emailAddressList.SelectedItem) 43 | { 44 | EmailAddress = (string)emailAddressList.SelectedItem; 45 | } 46 | DialogResult = DialogResult.OK; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Forms/AddEmailDialog.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/AddFaceDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | using System.IO; 11 | 12 | 13 | 14 | namespace OnGuardCore 15 | { 16 | public partial class AddFaceDialog : Form 17 | { 18 | 19 | public string FaceName { get; set; } 20 | public int Confidence { get; set; } 21 | 22 | public AddFaceDialog(FaceID face) 23 | { 24 | InitializeComponent(); 25 | 26 | string basePath = Storage.GetFilePath(string.Empty); 27 | basePath = Path.Combine(basePath, "Faces"); 28 | if (!Directory.Exists(basePath)) 29 | { 30 | Directory.CreateDirectory(basePath); 31 | } 32 | 33 | string[] existingNames = Directory.GetDirectories(basePath); 34 | foreach (string nameDir in existingNames) 35 | { 36 | if (basePath.Length < nameDir.Length) 37 | { 38 | string subDir = nameDir[(basePath.Length + 1)..]; 39 | FacesComboBox.Items.Add(subDir); 40 | } 41 | } 42 | 43 | if (FacesComboBox.Items.Count > 0) 44 | { 45 | if (null != face) 46 | { 47 | FacesComboBox.SelectedItem = face.Name; 48 | } 49 | } 50 | } 51 | 52 | private void CancelButton_Click(object sender, EventArgs e) 53 | { 54 | DialogResult = DialogResult.Cancel; 55 | } 56 | 57 | private void OKButton_Click(object sender, EventArgs e) 58 | { 59 | if (FacesComboBox.SelectedIndex != -1) 60 | { 61 | FaceName = (string)FacesComboBox.Items[FacesComboBox.SelectedIndex]; 62 | Confidence = (int)ConfidenceNumeric.Value; 63 | DialogResult = DialogResult.OK; 64 | } 65 | } 66 | } 67 | 68 | public class FaceID 69 | { 70 | public string Name { get; set; } 71 | public int Confidence { get; set; } 72 | public bool Selected { get; set; } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Forms/AddFaceDialog.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/AddUrlDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace OnGuardCore 5 | { 6 | 7 | /// 8 | /// A simple dialog to an an URL with a Cooldown. 9 | /// We could make the URLs global like the email addresses, but not for now 10 | /// 11 | public partial class AddUrlDialog : Form 12 | { 13 | 14 | public UrlOptions Options { get; } 15 | 16 | public AddUrlDialog(UrlOptions options) 17 | { 18 | InitializeComponent(); 19 | Options = options; 20 | if (null == options) 21 | { 22 | Options = new UrlOptions(string.Empty, 0, 300, 0); 23 | } 24 | else 25 | { 26 | urlText.Text = Options.Url; 27 | urlCoolDownNumeric.Value = Options.CoolDown.CooldownTime; 28 | WaitTimeNumeric.Value = Options.WaitTime; 29 | 30 | if ((Options.BIFlags & (int) BIFLAGS.Flagged) > 0) 31 | { 32 | FlagCheckBox.Checked = true; 33 | } 34 | 35 | if ((Options.BIFlags & (int) BIFLAGS.Confirmed) > 0) 36 | { 37 | ConfirmCheckBox.Checked = true; 38 | } 39 | 40 | if ((Options.BIFlags & (int) BIFLAGS.Reset) > 0) 41 | { 42 | ResetCheckBox.Checked = true; 43 | } 44 | } 45 | 46 | } 47 | 48 | private void OkButton_Click(object sender, EventArgs e) 49 | { 50 | if (string.IsNullOrEmpty(urlText.Text)) 51 | { 52 | MessageBox.Show(this, "You must enter an URL to notify (or we can't get there from here)!", "The URL Cannot be Empty!"); 53 | DialogResult = DialogResult.None; 54 | } 55 | else 56 | { 57 | Options.BIFlags = 0; 58 | Options.Url = urlText.Text; 59 | if (FlagCheckBox.Checked) Options.BIFlags |= (int) BIFLAGS.Flagged; 60 | if (ConfirmCheckBox.Checked) Options.BIFlags |= (int) BIFLAGS.Confirmed; 61 | if (ResetCheckBox.Checked) Options.BIFlags |= (int) BIFLAGS.Reset; 62 | Options.CoolDown.CooldownTime = (int) urlCoolDownNumeric.Value; 63 | Options.WaitTime = (int)WaitTimeNumeric.Value; 64 | DialogResult = DialogResult.OK; 65 | } 66 | } 67 | 68 | private void CancelButton_Click(object sender, EventArgs e) 69 | { 70 | DialogResult = DialogResult.Cancel; 71 | } 72 | 73 | private void AutoFillButton_Click(object sender, EventArgs e) 74 | { 75 | urlText.Text = "{Auto Fill}"; 76 | } 77 | 78 | private void ConfirmOnCheckChanged(object sender, EventArgs e) 79 | { 80 | } 81 | 82 | 83 | private void FlagCheckChanged(object sender, EventArgs e) 84 | { 85 | } 86 | 87 | 88 | private void ResetCheckBox_CheckedChanged(object sender, EventArgs e) 89 | { 90 | if (ResetCheckBox.Checked) 91 | { 92 | FlagCheckBox.Checked = false; 93 | ConfirmCheckBox.Checked = false; 94 | } 95 | } 96 | } 97 | 98 | [Flags] 99 | public enum BIFLAGS 100 | { 101 | Uncomfirmed = 0, 102 | Flagged = 1, 103 | Confirmed = 2, 104 | Reset = 4 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/Forms/AddUrlDialog.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/AnalysisSettingsDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace OnGuardCore 12 | { 13 | public partial class AnalysisSettingsDialog : Form 14 | { 15 | public AnalysisSettingsDialog() 16 | { 17 | InitializeComponent(); 18 | ParkedCarsOverlapCheckbox.Checked = Storage.Instance.GetGlobalBool("ExcludeParkedUsingOverlap", true); 19 | ExcludeParkedCornersCheckbox.Checked = Storage.Instance.GetGlobalBool("ExcludeParkedUsingCorners", true); 20 | BumpVehicleConfidenceCheck.Checked = Storage.Instance.GetGlobalBool("BumpMultiVehicleConfidence", true); 21 | } 22 | 23 | private void OKButton_Click(object sender, EventArgs e) 24 | { 25 | Storage.Instance.SetGlobalBool("ExcludeParkedUsingOverlap", ParkedCarsOverlapCheckbox.Checked); 26 | Storage.Instance.SetGlobalBool("ExcludeParkedUsingCorners", ExcludeParkedCornersCheckbox.Checked); 27 | Storage.Instance.SetGlobalBool("BumpMultiVehicleConfidence", BumpVehicleConfidenceCheck.Checked); 28 | Storage.Instance.Update(); 29 | DialogResult = DialogResult.OK; 30 | } 31 | 32 | private void CancelButton_Click(object sender, EventArgs e) 33 | { 34 | DialogResult = DialogResult.Cancel; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Forms/AnalysisSettingsDialog.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/BlueIrisSnapshot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace OnGuardCore 12 | { 13 | public partial class BlueIrisSnapshot : Form 14 | { 15 | string _shortCameraName; 16 | CameraData _camera; 17 | public string ShortCameraName { get => _shortCameraName; set => _shortCameraName = value; } 18 | 19 | public BlueIrisSnapshot(CameraData camera) 20 | { 21 | _camera = camera; 22 | InitializeComponent(); 23 | textBoxCameraName.Text = camera.Contact.CameraShortName; 24 | } 25 | 26 | private void OkButton_Click(object sender, EventArgs e) 27 | { 28 | ShortCameraName = textBoxCameraName.Text; 29 | DialogResult = DialogResult.OK; 30 | } 31 | 32 | private void CancelButton_Click(object sender, EventArgs e) 33 | { 34 | DialogResult = DialogResult.Cancel; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Forms/CleanupDialog.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/CreateAOI.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/DisplayMode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace OnGuardCore 12 | { 13 | public partial class DisplayMode : Form 14 | { 15 | public DisplayOption DisplayType { get; set; } 16 | public DisplayMode(DisplayOption display) 17 | { 18 | InitializeComponent(); 19 | 20 | if (display == DisplayOption.FilledHorizontally) 21 | { 22 | HorizontalFillRadio.Checked = true; 23 | } 24 | else if (display == DisplayOption.FilledVertically) 25 | { 26 | VerticalFillRadio.Checked = true; 27 | } 28 | else if (display == DisplayOption.FilledBoth) 29 | { 30 | FilledRadio.Checked = true; 31 | } 32 | else if (display == DisplayOption.Fixed) 33 | { 34 | FixedRadio.Checked = true; 35 | } 36 | 37 | } 38 | 39 | private void OKButton_Click(object sender, EventArgs e) 40 | { 41 | if (HorizontalFillRadio.Checked) 42 | { 43 | DisplayType = DisplayOption.FilledHorizontally; 44 | } 45 | else if (VerticalFillRadio.Checked) 46 | { 47 | DisplayType = DisplayOption.FilledVertically; 48 | } 49 | else if (FilledRadio.Checked) 50 | { 51 | DisplayType = DisplayOption.FilledBoth; 52 | } 53 | else if (FixedRadio.Checked) 54 | { 55 | DisplayType |= DisplayOption.Fixed; 56 | } 57 | 58 | DialogResult = DialogResult.OK; 59 | } 60 | 61 | private void CancelButton_Click(object sender, EventArgs e) 62 | { 63 | DialogResult = DialogResult.Cancel; 64 | } 65 | 66 | private void FilledRadio_CheckedChanged(object sender, EventArgs e) 67 | { 68 | 69 | } 70 | } 71 | 72 | public enum DisplayOption 73 | { 74 | FilledHorizontally, 75 | FilledBoth, 76 | Fixed, 77 | FilledVertically 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Forms/DisplayMode.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/EditAreasOfInterest.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/EmailAddressesDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows.Forms; 4 | 5 | namespace OnGuardCore 6 | { 7 | public partial class EmailAddressesDialog : Form 8 | { 9 | List Options { get; } 10 | public EmailAddressesDialog(List options) 11 | { 12 | InitializeComponent(); 13 | Options = options; 14 | 15 | if (options != null) 16 | { 17 | foreach (EmailOptions option in Options) 18 | { 19 | ListViewItem item = emailAddressList.Items.Add(option.EmailAddress); 20 | item.Tag = option; 21 | } 22 | } 23 | } 24 | 25 | private void OKButton_Click(object sender, EventArgs e) 26 | { 27 | Options.Clear(); 28 | foreach (ListViewItem item in emailAddressList.Items) 29 | { 30 | Options.Add((EmailOptions)item.Tag); 31 | } 32 | 33 | DialogResult = DialogResult.OK; 34 | } 35 | 36 | private void CancelButton_Click(object sender, EventArgs e) 37 | { 38 | DialogResult = DialogResult.Cancel; 39 | } 40 | 41 | private void AddButton_Click(object sender, EventArgs e) 42 | { 43 | using (CreateEmailAddressDialog dlg = new CreateEmailAddressDialog()) 44 | { 45 | DialogResult result = dlg.ShowDialog(); 46 | if (result == DialogResult.OK) 47 | { 48 | ListViewItem item = new ListViewItem(dlg.Email.EmailAddress) 49 | { 50 | Tag = dlg.Email 51 | }; 52 | emailAddressList.Items.Add(item); 53 | } 54 | } 55 | } 56 | 57 | private void EditButton_Click(object sender, EventArgs e) 58 | { 59 | if (emailAddressList.SelectedIndices.Count > 0) 60 | { 61 | using (CreateEmailAddressDialog dlg = new CreateEmailAddressDialog((EmailOptions)emailAddressList.Items[emailAddressList.SelectedIndices[0]].Tag)) 62 | { 63 | DialogResult result = dlg.ShowDialog(); 64 | if (result == DialogResult.OK) 65 | { 66 | emailAddressList.Items[emailAddressList.SelectedIndices[0]].Tag = dlg.Email; 67 | } 68 | } 69 | } 70 | } 71 | 72 | private void DeleteButton_Click(object sender, EventArgs e) 73 | { 74 | int index = emailAddressList.SelectedIndices[0]; 75 | AddButton.Focus(); 76 | emailAddressList.Items.RemoveAt(index); 77 | } 78 | 79 | private void OnSelectedIndexChanged(object sender, EventArgs e) 80 | { 81 | if (emailAddressList.SelectedIndices.Count > 0) 82 | { 83 | EditButton.Enabled = true; 84 | DeleteButton.Enabled = true; 85 | } 86 | else 87 | { 88 | EditButton.Enabled = false; 89 | DeleteButton.Enabled = false; 90 | } 91 | } 92 | 93 | private void OnActivate(object sender, EventArgs e) 94 | { 95 | EditButton_Click(sender, e); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Forms/EmailAddressesDialog.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/FaceDefinitionDialog.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | 61 | Face detection occurs in two stages. First, we identify people in the picture. Second, we pass just the picture(s) for the people to the AI. The AI then attempts to recognize the face(s) (if any). So, in step one we define the basic requirements for identifying people. 62 | 63 | -------------------------------------------------------------------------------- /src/Forms/FaceName.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Windows.Forms; 11 | 12 | namespace OnGuardCore 13 | { 14 | public partial class FaceName : Form 15 | { 16 | public String NameOfPerson { get; set; } 17 | public string Person { get; set; } 18 | 19 | string _basePath; 20 | 21 | public FaceName() 22 | { 23 | InitializeComponent(); 24 | 25 | _basePath = Storage.GetFilePath(string.Empty); 26 | _basePath = Path.Combine(_basePath, "Faces"); 27 | if (!Directory.Exists(_basePath)) 28 | { 29 | Directory.CreateDirectory(_basePath); 30 | } 31 | 32 | string[] existingNames = Directory.GetDirectories(_basePath); 33 | foreach (string nameDir in existingNames) 34 | { 35 | if (_basePath.Length < nameDir.Length) 36 | { 37 | string subDir = nameDir[(_basePath.Length + 1)..]; 38 | FacesComboBox.Items.Add(subDir); 39 | } 40 | } 41 | 42 | if (FacesComboBox.Items.Count > 0) 43 | { 44 | FacesComboBox.SelectedIndex = 0; 45 | } 46 | 47 | } 48 | 49 | private void OKButton_Click(object sender, EventArgs e) 50 | { 51 | 52 | string person = string.Empty; 53 | if (FacesComboBox.SelectedIndex != -1) 54 | { 55 | person = (string)FacesComboBox.SelectedItem; 56 | } 57 | else if (!string.IsNullOrEmpty(FacesComboBox.Text)) 58 | { 59 | person = (string)FacesComboBox.Text; 60 | } 61 | 62 | if (!string.IsNullOrEmpty(person)) 63 | { 64 | string fullPath = Path.Combine(_basePath, person); 65 | if (!Directory.Exists(fullPath)) 66 | { 67 | Directory.CreateDirectory(fullPath); 68 | } 69 | 70 | NameOfPerson = Path.Combine(fullPath, person + DateTime.Now.Ticks.ToString() + ".jpg"); 71 | Person = person; 72 | 73 | DialogResult = DialogResult.OK; 74 | } 75 | else 76 | { 77 | MessageBox.Show(this, "You must enter the name of the person!", "Name is Invalid!"); 78 | } 79 | } 80 | 81 | 82 | private void CancelButton_Click(object sender, EventArgs e) 83 | { 84 | NameOfPerson = string.Empty; 85 | DialogResult = DialogResult.Cancel; 86 | } 87 | 88 | private void AddButton_Click(object sender, EventArgs e) 89 | { 90 | FacesComboBox.Items.Add(FacesComboBox.Text); 91 | Directory.CreateDirectory(Path.Combine(_basePath, FacesComboBox.Text)); 92 | FacesComboBox.SelectedItem = FacesComboBox.Text; 93 | 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/Forms/FaceName.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/HTTPPresets.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace OnGuardCore 12 | { 13 | public partial class HTTPPresets : Form 14 | { 15 | CameraData _camera; 16 | public HTTPPresets(CameraData camera) 17 | { 18 | _camera = camera; 19 | InitializeComponent(); 20 | 21 | labelCurrentCamera.Text = "Current Camera: " + _camera.CameraPrefix; 22 | if (camera.Contact.PresetSettings.PresetList.Count > 0) 23 | { 24 | string str = camera.Contact.PresetSettings.PresetList[0].Command; 25 | if (str.Contains("[ADDRESS]")) // It should 26 | { 27 | int offset = str.IndexOf("[ADDRESS]"); 28 | offset += "[ADDRESS]".Length; 29 | str = str.Remove(0, offset); 30 | textBoxUrl.Text = str; 31 | } 32 | } 33 | } 34 | 35 | 36 | private void OKButton_Click(object sender, EventArgs e) 37 | { 38 | 39 | if (textBoxUrl.Text.Contains("http") || textBoxUrl.Text.Contains("[ADDRESS]")) 40 | { 41 | MessageBox.Show("Your URL must NOT contain either http or [ADDRESS]. These values will be added automatically", "Invalid URL Format!"); 42 | } 43 | else 44 | { 45 | 46 | if (textBoxUrl.Text.Contains("[PRESET]") || textBoxUrl.Text.Contains("[OFFSET=")) 47 | { 48 | 49 | if (!(textBoxUrl.Text.Contains("[PRESET]") && textBoxUrl.Text.Contains("[OFFSET="))) 50 | { 51 | 52 | DialogResult = DialogResult.OK; 53 | _camera.Contact.PresetSettings.PresetMethod = PTZMethod.HTTP; 54 | _camera.Contact.PresetSettings.PresetList.Clear(); 55 | _camera.Contact.PresetSettings.CameraMake = _camera.CameraPrefix.ToLower(); 56 | 57 | string str = textBoxUrl.Text; 58 | if (!textBoxUrl.Text.Contains("[ADDRESS]")) 59 | { 60 | str = "http://[ADDRESS]" + textBoxUrl.Text; 61 | } 62 | 63 | // Yes, each preset has the same contents -- there can be only one! 64 | for (int i = 0; i < 256; i++) 65 | { 66 | Preset preset = new (); 67 | preset.Name = "Preset " + i.ToString(); 68 | preset.Command = str; 69 | _camera.Contact.PresetSettings.PresetList.Add(preset); 70 | } 71 | } 72 | else 73 | { 74 | MessageBox.Show(this, "Your URL CANNOT contain BOTH [PRESET] OR [OFFSET=", "Invalid URL format"); 75 | } 76 | } 77 | else 78 | { 79 | MessageBox.Show(this, "Your URL must contain either [PRESET] OR [OFFSET=", "Invalid URL format"); 80 | } 81 | } 82 | 83 | } 84 | 85 | private void CancelButton_Click(object sender, EventArgs e) 86 | { 87 | DialogResult = DialogResult.Cancel; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Forms/HTTPptz.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace OnGuardCore 12 | { 13 | public partial class HTTPptz : Form 14 | { 15 | CameraData _camera; 16 | public HTTPptz(CameraData camera) 17 | { 18 | _camera = camera; 19 | InitializeComponent(); 20 | 21 | textBoxLeft.Text = _camera.Contact.HTTPPanLeft; 22 | textBoxRight.Text = _camera.Contact.HTTPPanRight; 23 | textBoxUp.Text = _camera.Contact.HTTPPanUp; 24 | textBoxDown.Text = _camera.Contact.HTTPPanDown; 25 | textBoxZoomIn.Text = _camera.Contact.HTTPZoomIn; 26 | textBoxZoomOut.Text = _camera.Contact.HTTPZoomOut; 27 | textBoxStop.Text = _camera.Contact.HTTPStop; 28 | } 29 | 30 | private void OKButton_Click(object sender, EventArgs e) 31 | { 32 | if (!string.IsNullOrEmpty(textBoxLeft.Text) && !string.IsNullOrEmpty(textBoxRight.Text)) 33 | { 34 | _camera.Contact.HTTPPanLeft = textBoxLeft.Text; 35 | _camera.Contact.HTTPPanRight = textBoxRight.Text; 36 | _camera.Contact.HTTPPanUp = textBoxUp.Text; 37 | _camera.Contact.HTTPPanDown = textBoxDown.Text; 38 | _camera.Contact.HTTPZoomIn = textBoxZoomIn.Text; 39 | _camera.Contact.HTTPZoomOut = textBoxZoomOut.Text; 40 | _camera.Contact.HTTPStop = textBoxStop.Text; 41 | _camera.Contact.PTZContactMethod = PTZMethod.HTTP; 42 | DialogResult = DialogResult.OK; 43 | } 44 | else 45 | { 46 | MessageBox.Show(this, "At a minimum you must provide a definition for Left and Right", "Missing Values!"); 47 | } 48 | } 49 | 50 | private void CancelButton_Click(object sender, EventArgs e) 51 | { 52 | 53 | if (!string.IsNullOrEmpty(textBoxLeft.Text) && !string.IsNullOrEmpty(textBoxRight.Text)) 54 | { 55 | if (MessageBox.Show(this, "You have made entries. Are you sure you wish to exit?", "Exit?", MessageBoxButtons.YesNo) == DialogResult.Yes) 56 | { 57 | DialogResult = DialogResult.Cancel; 58 | } 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Forms/HTTPptz.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/HelpBox.cs: -------------------------------------------------------------------------------- 1 | using Microsoft; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Data; 6 | using System.Drawing; 7 | using OnGuardCore.Src.Properties; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | using System.Windows.Forms; 13 | using System.Resources; 14 | using System.IO; 15 | using System.Reflection; 16 | 17 | namespace OnGuardCore 18 | { 19 | public partial class HelpBox : Form 20 | { 21 | public HelpBox(string title, Size size, string helpFileName) 22 | { 23 | InitializeComponent(); 24 | 25 | this.Size = size; 26 | 27 | // Microsoft Sans Serif; bold 10 28 | Font font = new ("Microsoft Sans Serif", 10.0F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point); 29 | Size strSize = TextRenderer.MeasureText(title, font); 30 | TitleLabel.Location = new Point(this.Width/2 - (strSize.Width)/2, 20); 31 | TitleLabel.Text = title; 32 | OKButton.Location = new Point(size.Width / 2 - OKButton.Width / 2, ClientRectangle.Height - OKButton.Height - 5); 33 | 34 | richTextBoxHelp.SelectAll(); 35 | 36 | this.richTextBoxHelp.SelectAll(); 37 | 38 | string resName = "OnGuardCore.Resources.HelpFiles." + helpFileName; 39 | var assembly = Assembly.GetExecutingAssembly(); 40 | 41 | using Stream stream = assembly.GetManifestResourceStream(resName); 42 | using StreamReader reader = new (stream); 43 | richTextBoxHelp.SelectedRtf = reader.ReadToEnd(); 44 | 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Forms/HelpBox.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/HttpSnapshot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace OnGuardCore 12 | { 13 | public partial class HttpSnapshot : Form 14 | { 15 | CameraData _camera; 16 | 17 | public HttpSnapshot(CameraData camera) 18 | { 19 | _camera = camera; 20 | InitializeComponent(); 21 | } 22 | 23 | private void OKButton_Click(object sender, EventArgs e) 24 | { 25 | _camera.Contact.JPGSnapshotURL = textBoxURL.Text; 26 | _camera.Contact.JpgContactMethod = PTZMethod.HTTP; 27 | DialogResult = DialogResult.OK; 28 | } 29 | 30 | private void CancelButton_Click(object sender, EventArgs e) 31 | { 32 | DialogResult = DialogResult.Cancel; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Forms/ISpyPTZ.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | 61 | Changes made to the URL text box will be applied to the URL in the Directions list above when you select a different direction or press OK. However, they will not (ever) be applied to the model list. 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/Forms/ISpySnapshot.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/ImageCaptureDialog.cs: -------------------------------------------------------------------------------- 1 | using OnGuardCore; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Data; 6 | using System.Drawing; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Windows.Forms; 11 | 12 | namespace OnGuardCore 13 | { 14 | public partial class ImageCaptureDialog : Form 15 | { 16 | CameraData _camera; 17 | public ImageCaptureDialog(CameraData camera) 18 | { 19 | _camera = camera; 20 | InitializeComponent(); 21 | 22 | int maxEvent = Storage.Instance.GetGlobalInt("MaxEventTime"); 23 | if (maxEvent != 0) 24 | { 25 | maxEventNumeric.Value = maxEvent; 26 | } 27 | 28 | int eventInterval = Storage.Instance.GetGlobalInt("EventInterval"); 29 | if (eventInterval != 0) 30 | { 31 | eventIntervalNumeric.Value = eventInterval; 32 | } 33 | 34 | double snapshot = Storage.Instance.GetGlobalDouble("FrameInterval"); 35 | if (snapshot != 0.0) 36 | { 37 | snapshotNumeric.Value = (decimal)snapshot; 38 | } 39 | 40 | } 41 | private void OKButton_Click(object sender, EventArgs e) 42 | { 43 | Storage.Instance.SetGlobalDouble("FrameInterval", (double)snapshotNumeric.Value); 44 | Storage.Instance.SetGlobalInt("MaxEventTime", (int)maxEventNumeric.Value); 45 | Storage.Instance.SetGlobalInt("EventInterval", (int)eventIntervalNumeric.Value); 46 | Storage.Instance.Update(); 47 | DialogResult = DialogResult.OK; 48 | } 49 | 50 | private void CancelButton_Click(object sender, EventArgs e) 51 | { 52 | DialogResult = DialogResult.Cancel; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Forms/InitialPictureBehaviorDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace OnGuardCore 12 | { 13 | public partial class InitialPictureBehaviorDialog : Form 14 | { 15 | public PictureDateBehavior Behavior { get; set; } 16 | 17 | public InitialPictureBehaviorDialog(PictureDateBehavior behavior, DateTime searchDate) 18 | { 19 | Behavior = behavior; 20 | InitializeComponent(); 21 | 22 | switch (Behavior) 23 | { 24 | case PictureDateBehavior.Picture1: 25 | radioButtonPicture1.Checked = true; 26 | break; 27 | 28 | case PictureDateBehavior.SearchDate: 29 | radioButtonEnteredDateTime.Checked = true; 30 | break; 31 | 32 | case PictureDateBehavior.LastViewed: 33 | radioButtonLastViewed.Checked = true; 34 | break; 35 | } 36 | 37 | if (searchDate == DateTime.MinValue) 38 | { 39 | radioButtonEnteredDateTime.Enabled = false; // You can't select this if there isn't one. 40 | } 41 | } 42 | 43 | 44 | private void ButtonCancel_Click(object sender, EventArgs e) 45 | { 46 | DialogResult = DialogResult.Cancel; 47 | this.Close(); 48 | } 49 | 50 | private void buttonOK_Click(object sender, EventArgs e) 51 | { 52 | DialogResult = DialogResult.OK; 53 | 54 | if (radioButtonPicture1.Checked) 55 | { 56 | Behavior = PictureDateBehavior.Picture1; 57 | } 58 | else if (radioButtonEnteredDateTime.Checked) 59 | { 60 | Behavior = PictureDateBehavior.SearchDate; 61 | } 62 | else 63 | { 64 | Behavior = PictureDateBehavior.LastViewed; 65 | } 66 | 67 | this.Close(); 68 | } 69 | } 70 | 71 | public enum PictureDateBehavior 72 | { 73 | Picture1, 74 | SearchDate, 75 | LastViewed 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Forms/InterestingItemsDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows.Forms; 4 | 5 | namespace OnGuardCore 6 | { 7 | public partial class InterestingItemsDialog : Form 8 | { 9 | public InterestingItemsDialog(AnalysisResult analysisResult) 10 | { 11 | InitializeComponent(); 12 | 13 | foreach (var interest in analysisResult.InterestingObjects) 14 | { 15 | ListViewItem item = new() 16 | { 17 | Text = interest.Area.AOIName 18 | }; 19 | 20 | double screenWidthPercent = Math.Round((100.0 * interest.ObjectRectangle.Width) / BitmapResolution.XResolution, 1, MidpointRounding.AwayFromZero); 21 | double screenHeightPercent = Math.Round((100.0 * interest.ObjectRectangle.Height) / BitmapResolution.YResolution, 1, MidpointRounding.AwayFromZero); 22 | 23 | item.SubItems.Add(interest.Area.AOIType.ToString()); 24 | item.SubItems.Add(interest.Label); 25 | item.SubItems.Add(interest.Confidence.ToString()); 26 | item.SubItems.Add(interest.Overlap.ToString()); 27 | item.SubItems.Add(screenWidthPercent.ToString()); 28 | item.SubItems.Add(screenHeightPercent.ToString()); 29 | 30 | interestingListView.Items.Add(item); 31 | 32 | } 33 | 34 | foreach (string item in analysisResult.FailureReasons) 35 | { 36 | failuresList.Items.Add(item); 37 | } 38 | 39 | 40 | } 41 | 42 | private void DoneButton_Click(object sender, EventArgs e) 43 | { 44 | DialogResult = DialogResult.OK; 45 | } 46 | 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Forms/InterestingItemsDialog.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/MMS-Helper.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | 61 | Note: If you try to send too many pictures or you don't resize your picture small enough your carrier may refuse to accept the message, or it may scale pictures down. Your carrier may or may not return any error messages to On Guard. 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/Forms/ModelessMessageWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace OnGuardCore 12 | { 13 | public partial class ModelessMessageWindow : Form 14 | { 15 | Timer _timer; 16 | public ModelessMessageWindow(Control parent, string title, string message, bool button) 17 | { 18 | 19 | _timer = new Timer(); 20 | _timer.Interval = 100; 21 | _timer.Tick += _timer_Tick; 22 | 23 | 24 | InitializeComponent(); 25 | SetLabel(title, message); 26 | if (button) 27 | { 28 | DismissButton.Visible = true; 29 | DismissButton.Enabled = true; 30 | } 31 | 32 | _timer.Start(); 33 | } 34 | 35 | private void _timer_Tick(object sender, EventArgs e) 36 | { 37 | if (this.WindowState == FormWindowState.Normal) 38 | { 39 | this.BringToFront(); 40 | this.Update(); 41 | } 42 | } 43 | 44 | 45 | private void Button_Click(object sender, EventArgs e) 46 | { 47 | _timer?.Stop(); 48 | this.Hide(); 49 | } 50 | 51 | public void SetLabel(string title, string message) 52 | { 53 | LabelMessage.Text = message; 54 | this.Text = title; 55 | var size = TextRenderer.MeasureText(message, LabelMessage.Font); 56 | if (size.Width > this.ClientRectangle.Width - 10) 57 | { 58 | this.Width = size.Width + 12; 59 | DismissButton.Left = (Width / 2) - DismissButton.Width / 2; 60 | } 61 | 62 | LabelMessage.Left = this.Width / 2 - size.Width / 2; 63 | this.Show(); 64 | this.BringToFront(); 65 | this.Update(); 66 | } 67 | 68 | public void Destroy() 69 | { 70 | DialogResult = DialogResult.None; 71 | this.Close(); 72 | } 73 | 74 | private void OnClosed(object sender, FormClosedEventArgs e) 75 | { 76 | DialogResult = DialogResult.None; 77 | } 78 | 79 | private void OnClosing(object sender, FormClosingEventArgs e) 80 | { 81 | DialogResult = DialogResult.None; 82 | } 83 | 84 | private void OnVisibleChanged(object sender, EventArgs e) 85 | { 86 | if (this.Visible) 87 | { 88 | this.BringToFront(); 89 | _timer?.Start(); 90 | } 91 | else 92 | { 93 | _timer?.Stop(); 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Forms/ModelessMessageWindow.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/ObjectDefinitionDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace OnGuardCore 12 | { 13 | public partial class ObjectDefinitionDialog : Form 14 | { 15 | public string ObjectType { get; set; } 16 | public int Confidence { get; set; } 17 | public int Overlap { get; set; } 18 | public int MinX { get; set; } 19 | public int MinY { get; set; } 20 | 21 | public ObjectDefinitionDialog() 22 | { 23 | InitializeComponent(); 24 | } 25 | 26 | public ObjectDefinitionDialog(ObjectCharacteristics src) 27 | { 28 | InitializeComponent(); 29 | 30 | if (null != src) 31 | { 32 | int index = ObjectCombo.FindString(src.ObjectType); 33 | ObjectCombo.SelectedIndex = index; 34 | ConfidenceNumeric.Value = src.Confidence; 35 | overlapNumeric.Value = src.MinPercentOverlap; 36 | minWidthNumeric.Value = src.MinimumXSize; 37 | minHeightNumeric.Value = src.MinimumYSize; 38 | } 39 | 40 | } 41 | 42 | private void OKButton_Click(object sender, EventArgs e) 43 | { 44 | if (ObjectCombo.SelectedIndex >= 0) 45 | { 46 | ObjectType = ObjectCombo.SelectedItem.ToString(); 47 | Confidence = (int)ConfidenceNumeric.Value; 48 | Overlap = (int)overlapNumeric.Value; 49 | MinX = (int)minWidthNumeric.Value; 50 | MinY = (int)minHeightNumeric.Value; 51 | DialogResult = DialogResult.OK; 52 | } 53 | else 54 | { 55 | MessageBox.Show(this, "You must select an item from the Object Type list!", "Select an Object!"); 56 | DialogResult = DialogResult.None; 57 | } 58 | } 59 | 60 | private void CancelButton_Click(object sender, EventArgs e) 61 | { 62 | DialogResult = DialogResult.Cancel; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Forms/ObjectDefinitionDialog.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/OnGuardDataDialog.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/OnVIFSnapshot.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/OutgoingEmailDialog.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/PictureDateSelect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace OnGuardCore 12 | { 13 | public partial class PictureDateSelect : Form 14 | { 15 | public DateTime SearchDateTime { get; set; } 16 | public bool KeepDateTime { get; set; } 17 | DateTime _currentPicture; 18 | TimeOnly _timeOnly; 19 | 20 | public PictureDateSelect(DateTime dateTime, DateTime currentPicture) 21 | { 22 | InitializeComponent(); 23 | 24 | _currentPicture = currentPicture; 25 | if (dateTime != DateTime.MinValue) 26 | { 27 | SearchDateTime = dateTime; 28 | } 29 | else 30 | { 31 | SearchDateTime = DateTime.Now; 32 | } 33 | 34 | PictureDate.Value = SearchDateTime.Date; 35 | PictureTime.Value = SearchDateTime; 36 | 37 | } 38 | 39 | private void CancelButton_Click(object sender, EventArgs e) 40 | { 41 | DialogResult = DialogResult.Cancel; 42 | this.Close(); 43 | } 44 | 45 | private void OKButton_Click(object sender, EventArgs e) 46 | { 47 | SearchDateTime = new DateTime(PictureDate.Value.Year, PictureDate.Value.Month, PictureDate.Value.Day, PictureTime.Value.Hour, PictureTime.Value.Minute, PictureTime.Value.Second); ; 48 | KeepDateTime = KeepDateCheckbox.Checked; 49 | DialogResult = DialogResult.OK; 50 | this.Close(); 51 | } 52 | 53 | private void CurrentPictureButton_Click(object sender, EventArgs e) 54 | { 55 | PictureDate.Value = _currentPicture.Date; 56 | PictureTime.Value = _currentPicture.ToLocalTime(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Forms/PictureDateSelect.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/ScheduledPreset.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/SetLogLevelDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace OnGuardCore 12 | { 13 | public partial class SetLogLevelDialog : Form 14 | { 15 | public SetLogLevelDialog() 16 | { 17 | InitializeComponent(); 18 | 19 | switch (Dbg.Level) 20 | { 21 | case (int)LogLevel.Verbose: 22 | radioVerbose.Checked = true; 23 | break; 24 | 25 | case (int)LogLevel.DetailedInfo: 26 | radioDetailedInfo.Checked = true; 27 | break; 28 | 29 | case (int)LogLevel.Info: 30 | radioInfo.Checked = true; 31 | break; 32 | 33 | case (int)LogLevel.Warning: 34 | radioWarning.Checked = true; 35 | break; 36 | 37 | case (int)(LogLevel.Error): 38 | radioError.Checked = true; 39 | break; 40 | 41 | } 42 | } 43 | 44 | private void OK_Click(object sender, EventArgs e) 45 | { 46 | if (radioVerbose.Checked) 47 | { 48 | Dbg.SetLogLevel(LogLevel.Verbose); 49 | } 50 | else if (radioDetailedInfo.Checked) 51 | { 52 | Dbg.SetLogLevel(LogLevel.DetailedInfo); 53 | } 54 | else if (radioInfo.Checked) 55 | { 56 | Dbg.SetLogLevel(LogLevel.Info); 57 | } 58 | else if (radioWarning.Checked) 59 | { 60 | Dbg.SetLogLevel(LogLevel.Warning); 61 | } 62 | else if (radioError.Checked) 63 | { 64 | Dbg.SetLogLevel(LogLevel.Error); 65 | } 66 | 67 | Storage.Instance.SetGlobalInt("LogLevel", (int)Dbg.Level); // yes, we just set it 68 | Storage.Instance.Update(); 69 | this.Close(); 70 | } 71 | 72 | private void CancelButton_Click(object sender, EventArgs e) 73 | { 74 | this.Close(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Forms/SettingsDialog.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/StartRestartAI.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace OnGuardCore 12 | { 13 | public partial class StartRestartAI : Form 14 | { 15 | public bool AIRunning { get; set; } 16 | public StartRestartAI() 17 | { 18 | InitializeComponent(); 19 | 20 | if (!AI.IsAIRunning()) 21 | { 22 | StatusLabel.Text = "NOT Running"; 23 | StopButton.Enabled = false; 24 | StartButton.Text = "Start"; 25 | } 26 | else 27 | { 28 | AIRunning = true; 29 | StartButton.Text = "Restart"; 30 | StopButton.Enabled = true; 31 | } 32 | } 33 | 34 | private void DoneButton_Click(object sender, EventArgs e) 35 | { 36 | DialogResult = DialogResult.OK; 37 | } 38 | 39 | private void StartButton_Click(object sender, EventArgs e) 40 | { 41 | if (MessageBox.Show(this, "Starting/Restarting/Stopping the DeepStack AI may result in application instability. Proceeed?", "Warning!", MessageBoxButtons.YesNo) == DialogResult.Yes) 42 | { 43 | AIRunning = AI.RestartAI(true, true); 44 | 45 | if (AIRunning) 46 | { 47 | StatusLabel.Text = "Running"; 48 | StopButton.Enabled = true; 49 | } 50 | else 51 | { 52 | StatusLabel.Text = "NOT Running - Start/Restart Failed"; 53 | StopButton.Enabled = false; 54 | StartButton.Text = "Start"; 55 | } 56 | } 57 | } 58 | 59 | private void StopButton_Click(object sender, EventArgs e) 60 | { 61 | if (MessageBox.Show(this, "Starting/Restarting/Stopping the DeepStack AI may result in application instability. Proceeed?", "Warning!", MessageBoxButtons.YesNo) == DialogResult.Yes) 62 | { 63 | AIRunning = false; 64 | AI.StopAI(); 65 | StatusLabel.Text = "NOT Running"; 66 | StopButton.Enabled = false; 67 | StartButton.Text = "Start"; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Forms/StartRestartAI.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/SyncToDatabaseDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace OnGuardCore 12 | { 13 | public partial class SyncToDatabaseDialog : Form 14 | { 15 | private double _interval; 16 | public double Interval { get => _interval; } 17 | 18 | public SyncToDatabaseDialog() 19 | { 20 | InitializeComponent(); 21 | } 22 | 23 | private void OkButton_Click(object sender, EventArgs e) 24 | { 25 | _interval = (double)IntervalNumeric.Value; 26 | DialogResult = DialogResult.OK; 27 | } 28 | 29 | private void CancelButton_Click(object sender, EventArgs e) 30 | { 31 | DialogResult = DialogResult.Cancel; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Forms/Test Email Address.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace OnGuardCore 12 | { 13 | public partial class TestEmailAddress : Form 14 | { 15 | public TestEmailAddress() 16 | { 17 | InitializeComponent(); 18 | } 19 | 20 | private void OKButton_Click(object sender, EventArgs e) 21 | { 22 | DialogResult = DialogResult.OK; 23 | Close(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Forms/Test Email Address.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/TestPIcturesDialog.cs: -------------------------------------------------------------------------------- 1 | using OnGuardCore.Src.Properties; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Data; 7 | using System.Drawing; 8 | using System.Drawing.Imaging; 9 | using System.Globalization; 10 | using System.IO; 11 | using System.Linq; 12 | using System.Resources; 13 | using System.Text; 14 | using System.Threading.Tasks; 15 | using System.Windows.Forms; 16 | 17 | namespace OnGuardCore 18 | { 19 | public partial class TestPIcturesDialog : Form 20 | { 21 | CameraCollection _cameras; 22 | public TestPIcturesDialog(CameraCollection cameras) 23 | { 24 | _cameras = cameras; 25 | InitializeComponent(); 26 | CameraData cam; 27 | 28 | ((ListBox)this.checkedListBoxCameras).DataSource = _cameras.CameraDictionary.Values.ToArray(); 29 | ((ListBox)this.checkedListBoxCameras).DisplayMember = "CameraPrefix"; 30 | 31 | for (int i = 0; i < checkedListBoxCameras.Items.Count; i++) 32 | { 33 | checkedListBoxCameras.SetItemChecked(i, true); 34 | } 35 | } 36 | 37 | private void ButtonOK_Click(object sender, EventArgs e) 38 | { 39 | 40 | ResourceSet allPics = SamplePictureResources.ResourceManager.GetResourceSet(CultureInfo.InvariantCulture, true, true); 41 | 42 | foreach (int itemChecked in checkedListBoxCameras.CheckedIndices) 43 | { 44 | CameraData camera = (CameraData)(checkedListBoxCameras.Items[itemChecked]); 45 | 46 | IDictionaryEnumerator dict = allPics.GetEnumerator(); 47 | 48 | while (dict.MoveNext()) 49 | { 50 | Bitmap bm = (Bitmap)dict.Value; 51 | using MemoryStream mem = new(); 52 | string fullPath = CameraData.PathAndPrefix(camera); 53 | fullPath += DateTime.Now.Ticks.ToString() + ".jpg"; 54 | bm.Save(fullPath, ImageFormat.Jpeg); 55 | } 56 | } 57 | 58 | DialogResult = DialogResult.OK; 59 | this.Close(); 60 | } 61 | 62 | private void ButtonCancel_Click(object sender, EventArgs e) 63 | { 64 | 65 | DialogResult = DialogResult.Cancel; 66 | this.Close(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Forms/TestPIcturesDialog.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/TestPresets.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /src/Forms/iSpyPreset.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | 61 | 17, 17 62 | 63 | -------------------------------------------------------------------------------- /src/FrameAccumulator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace OnGuardCore 8 | { 9 | 10 | public abstract class FrameAccumulator : IDisposable 11 | { 12 | 13 | public delegate void EmailAccumulated(SortedList frames); 14 | 15 | SortedList Frames { get; set; } 16 | 17 | protected readonly object _lock = new (); 18 | public int TimeToAccumulate { get; set; } 19 | protected bool DisposedValue { get => disposedValue; set => disposedValue = value; } 20 | 21 | protected System.Threading.Timer _timer; 22 | private bool disposedValue = false; // To detect redundant calls 23 | 24 | 25 | public void Init(int timeToAccumulate) 26 | { 27 | TimeToAccumulate = timeToAccumulate; 28 | Frames = new SortedList(); 29 | } 30 | 31 | public void Add(Frame frame) 32 | { 33 | lock (_lock) 34 | { 35 | Frames.Add(frame.Item.TimeEnqueued, frame); 36 | if (null == _timer) 37 | { 38 | _timer = new System.Threading.Timer(DoneAccumulating, null, TimeToAccumulate * 1000, 0); 39 | } 40 | } 41 | 42 | } 43 | 44 | // This triggers when the timer expires or when we have the number of frames we were expecting 45 | void DoneAccumulating(object obj) 46 | { 47 | lock (_lock) 48 | { 49 | _timer = null; 50 | 51 | if (Frames.Values.Count > 0) 52 | { 53 | lock (Frames.Values[0].Item.CamData.AccumulateLock) 54 | { 55 | Frames.Values[0].Item.CamData.Accumulating = false; // no longer accumulating 56 | Frames.Values[0].Item.CamData.TimeLastAccumulatorCompleted = DateTime.Now; 57 | } 58 | } 59 | 60 | List aCopy = new (); 61 | 62 | foreach (Frame frame in Frames.Values) 63 | { 64 | Frame cpy = new (frame); 65 | aCopy.Add(cpy); 66 | } 67 | 68 | ProcessAccumulatedFrames(aCopy); 69 | Frames.Clear(); 70 | } 71 | } 72 | 73 | 74 | 75 | protected virtual void Dispose(bool disposing) 76 | { 77 | if (!DisposedValue) 78 | { 79 | if (disposing) 80 | { 81 | lock (_lock) 82 | { 83 | if (_timer != null) _timer.Dispose(); 84 | } 85 | } 86 | 87 | DisposedValue = true; 88 | } 89 | } 90 | 91 | 92 | public void Dispose() 93 | { 94 | Dispose(true); 95 | GC.SuppressFinalize(this); 96 | } 97 | 98 | public abstract void ProcessAccumulatedFrames(List frames); 99 | 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/GlobalData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.IO; 7 | 8 | namespace OnGuardCore 9 | { 10 | public static class GlobalData 11 | { 12 | public static int AreaGridX { get => 64; } // may be settable in the future 13 | public static int AreaGridY { get => 64; } 14 | 15 | } 16 | 17 | public static class GlobalFunctions 18 | { 19 | public static string GetUniqueFileName(string fileName) 20 | { 21 | string result = string.Empty; 22 | if (!string.IsNullOrEmpty(fileName)) 23 | { 24 | FileInfo fi = new FileInfo(fileName); 25 | if (fi.Exists) 26 | { 27 | long fileTime = fi.CreationTime.ToFileTime(); 28 | result = GetFileKey(fi, fileName); 29 | } 30 | } 31 | 32 | return result; 33 | } 34 | 35 | public static string GetFileKey(FileInfo fi, string fileName) 36 | { 37 | string result = string.Empty; 38 | if (!string.IsNullOrEmpty(fileName)) 39 | { 40 | long fileTime = fi.CreationTime.ToFileTime(); 41 | result = $"{fileTime,0:0000000000000000000}-{Path.GetFileName(fileName).ToLower()}"; 42 | result = result.ToLower(); 43 | } 44 | 45 | return result; 46 | } 47 | 48 | public static string GetComparisonKey(DateTime compTime) 49 | { 50 | string result = string.Empty; 51 | long fileTime = compTime.ToFileTime(); 52 | result = $"{fileTime,0:0000000000000000000}-"; 53 | return result; 54 | } 55 | 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | 6 | using System.Diagnostics.CodeAnalysis; 7 | 8 | [assembly: SuppressMessage("Usage", "CA2200:Rethrow to preserve stack details.", Justification = "", Scope = "member", Target = "~M:OnGuardCore.AIAnalyzer.AIProcessFromUI(System.IO.Stream,System.String)~System.Threading.Tasks.Task{System.Collections.Generic.List{OnGuardCore.InterestingObject}}")] 9 | [assembly: SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "", Scope = "member", Target = "~P:OnGuardCore.InterestingObject.Y_min")] 10 | [assembly: SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "", Scope = "member", Target = "~P:OnGuardCore.InterestingObject.X_min")] 11 | [assembly: SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "", Scope = "member", Target = "~P:OnGuardCore.InterestingObject.Y_max")] 12 | [assembly: SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "", Scope = "member", Target = "~P:OnGuardCore.InterestingObject.X_max")] 13 | [assembly: SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "", Scope = "member", Target = "~F:OnGuardCore.AreaOfInterest.AreaRect")] 14 | [assembly: SuppressMessage("Usage", "CA2200:Rethrow to preserve stack details.", Justification = "", Scope = "member", Target = "~M:OnGuardCore.MainWindow.LoadImage(System.String)~System.Collections.Generic.List{OnGuardCore.InterestingObject}")] 15 | [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:OnGuardCore.MainWindow.PresetButton_Click(System.Object,System.EventArgs)")] 16 | [assembly: SuppressMessage("Reliability", "CA2007:Consider calling ConfigureAwait on the awaited task", Justification = "", Scope = "member", Target = "~M:OnGuardCore.MQTTPublish.CreateClient~System.Threading.Tasks.Task")] 17 | [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:OnGuardCore.MQTTPublish.Connect~System.Threading.Tasks.Task")] 18 | [assembly: SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "", Scope = "member", Target = "~F:OnGuardCore.EmailOptions.DaysOfWeek")] 19 | [assembly: SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "", Scope = "member", Target = "~F:OnGuardCore.CameraData.AOI")] 20 | [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:OnGuardCore.EmailAccumulator.SendEmailAsync(System.String,System.String[],System.String[])~System.Threading.Tasks.Task")] 21 | [assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:OnGuardCore.MainWindow.InsertMotionIfNecessary(System.String)")] 22 | -------------------------------------------------------------------------------- /src/IStorage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.Win32; 4 | 5 | namespace OnGuardCore 6 | { 7 | public interface IStorage 8 | { 9 | void CreateBaseTree(); 10 | void DeleteArea(string cameraPath, string cameraPrefix, AreaOfInterest area); 11 | AILocation GetAILocation(); 12 | SortedDictionary GetAllAreas(string cameraPath, string cameraPrefix); 13 | CameraCollection GetAllCameras(); 14 | string GetAppVersion(); 15 | int GetCameraInt(string cameraPath, string cameraPrefix, string keyName); 16 | List GetEmailAddresses(); 17 | object GetValue(string keyName); 18 | bool GetGlobalBool(string keyName); 19 | bool GetGlobalBool(string keyName, bool useDefault); 20 | double GetGlobalDouble(string keyName); 21 | int GetGlobalInt(string keyName); 22 | int GetGlobalIntWithDefault(string keyName, int defaultValue); 23 | int GetGlobalIntExcept(string keyName); 24 | string GetGlobalString(string keyName); 25 | string GetGlobalStringNull(string keyName); 26 | void RemoveGlobalValue(string valueName); 27 | void SaveAllAreas(string cameraPath, string cameraPrefix, AreasOfInterestCollection areas); 28 | void SaveArea(AreaOfInterest area); 29 | void SaveArea(CameraData cam, AreaOfInterest area); 30 | void SaveArea(string cameraPath, string cameraPrefix, AreaOfInterest area); 31 | void SaveCameras(CameraCollection allCameras); 32 | void SaveEmailAddresses(List addresses); 33 | void SetAILocation(string ipAddress, int port); 34 | void SetAppVersion(string version); 35 | void SetCameraInt(string cameraPath, string cameraPrefix, string keyName, int theValue); 36 | void SetGlobalBool(string keyName, bool value); 37 | void SetGlobalDouble(string keyName, double value); 38 | void SetGlobalInt(string keyName, int value); 39 | void SetGlobalString(string keyName, string value); 40 | void Update(); 41 | } 42 | } -------------------------------------------------------------------------------- /src/ImageObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace OnGuardCore 9 | { 10 | public class InterestingObject 11 | { 12 | public InterestingObject() 13 | { 14 | ID = Guid.NewGuid(); 15 | Label = "none"; 16 | 17 | // Some unnecessary initializations, but... 18 | Success = false; 19 | InMotion = false; 20 | Confidence = 80.0; 21 | X_min = 0; 22 | Y_min = 0; 23 | X_max = 0; 24 | Y_max = 0; 25 | IsFace = false; 26 | } 27 | 28 | public bool Success { get; set; } 29 | public string Label { get; set; } 30 | public double Confidence { get; set; } 31 | public int Y_min { get; set; } 32 | public int X_min { get; set; } 33 | public int Y_max { get; set; } 34 | public int X_max { get; set; } 35 | public Rectangle ObjectRectangle { get; set; } 36 | public bool InMotion { get; set; } 37 | public Guid ID { get; set; } 38 | public bool IsFace { get; set; } 39 | public AreaOfInterest Area { get; set; } 40 | public int Overlap { get; set; } 41 | public bool IsOfCameraInterest { get; set; } 42 | 43 | 44 | public InterestingObject(InterestingObject src) 45 | { 46 | if (src != null) 47 | { 48 | Label = src.Label; 49 | Success = src.Success; 50 | Confidence = src.Confidence; 51 | Y_max = src.Y_max; 52 | Y_min = src.Y_min; 53 | X_max = src.X_max; 54 | X_min = src.Y_min; 55 | ObjectRectangle = src.ObjectRectangle; 56 | InMotion = src.InMotion; 57 | ID = src.ID; 58 | IsFace = src.IsFace; 59 | 60 | } 61 | } 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/MostRecentCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace OnGuardCore 5 | { 6 | 7 | /// 8 | /// A class to clollect a list of recent values. 9 | /// In this case it is used to track AI processing time 10 | /// so we can average them out. 11 | /// 12 | public class MostRecentCollection : List 13 | { 14 | public int MaxItems { get; } 15 | readonly object _lock = new object(); 16 | 17 | public MostRecentCollection(int numberOfItems) 18 | { 19 | MaxItems = numberOfItems; 20 | } 21 | 22 | public void AddValue(double v) 23 | { 24 | lock (_lock) 25 | { 26 | if (Count == MaxItems) 27 | { 28 | RemoveAt(0); 29 | } 30 | 31 | Add(v); 32 | } 33 | } 34 | 35 | public double Avg() 36 | { 37 | double result; 38 | 39 | lock (_lock) 40 | { 41 | result = 0.0; 42 | 43 | if (Count > 0) 44 | { 45 | result = this.Average(); 46 | } 47 | 48 | } 49 | return result; 50 | } 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/MotionDatabase.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Data.Sqlite; 2 | using Microsoft.EntityFrameworkCore; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace OnGuardCore 10 | { 11 | public class MotionDBContext : DbContext 12 | { 13 | static string s_connectionString; 14 | static bool s_setWalMode = false; 15 | 16 | public static void SetupDatabase(string dbPath) 17 | { 18 | s_connectionString = $@"Data Source={dbPath}\MotionInfo.db"; 19 | 20 | bool exists = DoesMotionDatabaseExist($@"{dbPath}\MotionInfo.db"); 21 | if (!exists) 22 | { 23 | CreateMotionDatabase(); 24 | } 25 | } 26 | 27 | public MotionDBContext() 28 | { 29 | if (!s_setWalMode) 30 | { 31 | using var connection = this.Database.GetDbConnection(); 32 | connection.Open(); 33 | using (var command = connection.CreateCommand()) 34 | { 35 | command.CommandText = "PRAGMA journal_mode=WAL;"; 36 | command.ExecuteNonQuery(); 37 | } 38 | } 39 | } 40 | 41 | 42 | protected override void OnConfiguring(DbContextOptionsBuilder dbContextOptionsBuilder) 43 | { 44 | dbContextOptionsBuilder.UseSqlite(s_connectionString); 45 | } 46 | 47 | public DbSet MotionInfo { get; set; } 48 | 49 | public static void CreateMotionDatabase() 50 | { 51 | try 52 | { 53 | using SqliteConnection con = new(s_connectionString); 54 | con.Open(); 55 | using SqliteCommand cmd = con.CreateCommand(); 56 | 57 | cmd.CommandText = "CREATE TABLE MotionInfo " + 58 | "(UniqueName VARCHAR(100) PRIMARY KEY DESC, " + 59 | "FileName VARCHAR(256), " + 60 | "Path VARCHAR(2056), " + 61 | "Camera VARCHAR(100), " + 62 | "PictureTime DATETIME);"; 63 | 64 | cmd.ExecuteNonQuery(); 65 | 66 | cmd.CommandText = "CREATE UNIQUE INDEX idxReverseUniqueName on MotionInfo (UniqueName ASC);"; 67 | cmd.ExecuteNonQuery(); 68 | } 69 | catch (Exception ex) 70 | { 71 | Dbg.Write(LogLevel.Error, "Exception - MotionDatabase - CreateMotionDatabase: " + ex.Message); 72 | } 73 | } 74 | 75 | public static bool DoesMotionDatabaseExist(string dbPath) 76 | { 77 | bool result = false; 78 | 79 | if (System.IO.File.Exists(dbPath)) 80 | { 81 | result = true; 82 | 83 | using SqliteConnection con = new(s_connectionString); 84 | con.Open(); 85 | 86 | try 87 | { 88 | string query = "SELECT name FROM sqlite_master WHERE type='table' AND name='MotionInfo';"; 89 | using SqliteCommand cmd = con.CreateCommand(); 90 | cmd.CommandText = query; 91 | var queryResult = cmd.ExecuteScalar(); 92 | if (null != queryResult) 93 | { 94 | result = true; 95 | } 96 | } 97 | catch (Exception ex) 98 | { 99 | result = false; 100 | } 101 | } 102 | return result; 103 | } 104 | } 105 | } 106 | 107 | 108 | -------------------------------------------------------------------------------- /src/ObjectCharacteristics.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace OnGuardCore 8 | { 9 | 10 | /// 11 | /// When defining an Area of Interest each object type in an area has optional 12 | /// characteristics that define when an object on the screen is consdiered 13 | /// "Interesting" 14 | /// 15 | [Serializable] 16 | public class ObjectCharacteristics 17 | { 18 | private string objectType; 19 | public int Confidence { get; set; } // Confidence values are very good in defining "people". 20 | public int MinPercentOverlap { get; set; } // A measurement for how much of an object must overlap the Area of Interest to be considered Interesting 21 | public int TimeFrame { get; set; } // Currently not implemented. When we determine movement direction this will define how many frames we look in 22 | public int MinimumXSize { get; set; } //In part this regulates how close the object is to the camera. I don't see a reason for maximum size 23 | public int MinimumYSize { get; set; } //In part this regulates how close the object is to the camera. I don't see a reason for maximum size 24 | 25 | public List Faces {get; set;} 26 | 27 | public string ObjectType { get => objectType; set => objectType = value; } 28 | 29 | public Guid ID { get; set; } 30 | 31 | public ObjectCharacteristics() 32 | { 33 | ID = Guid.NewGuid(); 34 | objectType = "person"; 35 | Confidence = 90; 36 | MinPercentOverlap = 50; 37 | TimeFrame = 1; 38 | MinimumXSize = 0; 39 | MinimumYSize = 0; 40 | Faces = new List(); 41 | } 42 | 43 | public ObjectCharacteristics(ObjectCharacteristics src) 44 | { 45 | ID = src.ID; 46 | objectType = src.objectType; 47 | Confidence = src.Confidence; 48 | MinPercentOverlap = src.MinPercentOverlap; 49 | TimeFrame = src.TimeFrame; 50 | MinimumXSize = src.MinimumXSize; 51 | MinimumYSize = src.MinimumYSize; 52 | Faces = src.Faces; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/PendingItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Drawing; 4 | 5 | namespace OnGuardCore 6 | { 7 | /// 8 | /// A class to store information for recently changed/motion files. 9 | /// It tracks that information through the whole process of sending the information 10 | /// to the AI 11 | /// 12 | public class PendingItem : IDisposable 13 | { 14 | private bool disposedValue; 15 | 16 | public string CameraPath { get; } 17 | public string PendingFile { get; set; } // The file we want the AI to look at 18 | public Bitmap PictureImage{ get; set; } 19 | public DateTime TimeEnqueued { get; set; } // The time we put it in the queue waiting for the AI 20 | public DateTime TimeDispatched { get; set; } // The time the queue dispatched it to the AI 21 | public DateTime TimeCompleted { get; set; } // The time the AI completed the project and returned the item list 22 | public CameraData CamData { get; set; } 23 | 24 | 25 | public PendingItem(CameraData camData, string fileName) 26 | { 27 | CamData = camData; 28 | PendingFile = fileName; 29 | TimeEnqueued = DateTime.Now; // we only create one when we are ready to put it in the queue 30 | TimeCompleted = TimeEnqueued; 31 | TimeDispatched = TimeEnqueued; 32 | } 33 | 34 | public TimeSpan TimeInQueue() 35 | { 36 | return DateTime.Now - TimeEnqueued; 37 | } 38 | 39 | // Only call this when we are are ready to dispatch the item to the AI 40 | // It also (lamely) returns the time so far 41 | public TimeSpan TimeToDispatch() 42 | { 43 | TimeDispatched = DateTime.Now; 44 | return TimeDispatched - TimeEnqueued; 45 | } 46 | 47 | public TimeSpan SetTimeProcessingByAI() 48 | { 49 | TimeCompleted = DateTime.Now; 50 | return TimeCompleted - TimeDispatched; 51 | } 52 | 53 | public TimeSpan TotalProcessingTime() 54 | { 55 | TimeSpan result = TimeCompleted - TimeEnqueued; 56 | return result; 57 | } 58 | 59 | public TimeSpan AIProcessingTime() 60 | { 61 | TimeSpan result = TimeCompleted - TimeDispatched; 62 | return result; 63 | } 64 | 65 | protected virtual void Dispose(bool disposing) 66 | { 67 | if (!disposedValue) 68 | { 69 | if (disposing) 70 | { 71 | // dispose managed state (managed objects) 72 | // for now we will manually dispose the PictureImage when done with the bitmap 73 | /*if (null != PictureImage) 74 | { 75 | PictureImage.Dispose(); 76 | }*/ 77 | } 78 | 79 | disposedValue = true; 80 | } 81 | } 82 | 83 | public void Dispose() 84 | { 85 | // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method 86 | Dispose(disposing: true); 87 | GC.SuppressFinalize(this); 88 | } 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/PictureComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace OnGuardCore 8 | { 9 | public class PictureComparer : IComparer 10 | { 11 | public PictureOrder Order { get; set; } 12 | 13 | public PictureComparer() 14 | { 15 | Order = PictureOrder.Decending; 16 | } 17 | 18 | public void Reverse() 19 | { 20 | if (Order == PictureOrder.Ascending) 21 | { 22 | Order = PictureOrder.Decending; 23 | } 24 | else 25 | { 26 | Order = PictureOrder.Ascending; 27 | } 28 | } 29 | 30 | public int Compare(string first, string second) 31 | { 32 | int result = string.Compare(first, second); 33 | 34 | if (Order == PictureOrder.Decending) 35 | { 36 | result = 0 - result; 37 | } 38 | 39 | return result; 40 | } 41 | 42 | } 43 | 44 | public enum PictureOrder 45 | { 46 | Ascending, 47 | Decending 48 | } 49 | } 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/PictureInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.IO; 6 | using System.Threading.Tasks; 7 | 8 | namespace OnGuardCore 9 | { 10 | public class PictureInfo 11 | { 12 | public string FileName { get; } 13 | public string PictureKey { get; } 14 | public DateTime FileTime { get; set; } 15 | 16 | public PictureInfo(string fileName) 17 | { 18 | FileName = fileName.ToLower(); 19 | FileInfo fi = new FileInfo(fileName); 20 | PictureKey = GlobalFunctions.GetFileKey(fi, fileName); 21 | FileTime = fi.CreationTime; 22 | } 23 | 24 | public override string ToString() 25 | { 26 | return FileName; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/PictureMotionInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace OnGuardCore 9 | { 10 | public class PictureMotionInfo 11 | { 12 | public PictureMotionInfo(string uniqueName, string fileName, string path, string camera, DateTime pictureTime) 13 | { 14 | UniqueName = uniqueName; 15 | FileName = fileName; 16 | Path = path; 17 | Camera = camera; 18 | PictureTime = pictureTime; 19 | } 20 | 21 | [Key] 22 | [Required] 23 | public string UniqueName { get; set; } 24 | 25 | [Required] 26 | [MaxLength(256)] 27 | public string FileName { get; set; } // The name of the file without path 28 | 29 | [Required] 30 | [MaxLength(2056)] 31 | public string Path { get; set; } // The path without name 32 | 33 | [Required] 34 | [MaxLength(100)] 35 | public string Camera { get; set; } 36 | 37 | [Required] 38 | public DateTime PictureTime { get; set; } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | using System.Drawing; 7 | 8 | namespace OnGuardCore 9 | { 10 | static class Program 11 | { 12 | /// 13 | /// The main entry point for the application. 14 | /// 15 | [STAThread] 16 | static void Main() 17 | { 18 | MainWindow main = null; 19 | 20 | Application.SetHighDpiMode(HighDpiMode.DpiUnawareGdiScaled); 21 | Application.EnableVisualStyles(); 22 | Font defaultFont = new ("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); 23 | Application.SetDefaultFont(defaultFont); 24 | Application.SetCompatibleTextRenderingDefault(false); 25 | 26 | #if !DEBUG 27 | try 28 | #endif 29 | { 30 | Application.Run(main = new MainWindow()); 31 | } 32 | #if !DEBUG 33 | catch (ObjectDisposedException) 34 | { 35 | } 36 | 37 | catch (Exception ex) 38 | { 39 | MessageBox.Show("There was an unexpected error in On Guard. Please report the following information: " + ex.Message, "Unexpected Error!"); 40 | } 41 | finally 42 | { 43 | main?.Dispose(); 44 | } 45 | #endif 46 | 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Resources/Icons/Guardian.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Icons/Guardian.ico -------------------------------------------------------------------------------- /src/Resources/Icons/arrow-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Icons/arrow-down.png -------------------------------------------------------------------------------- /src/Resources/Icons/arrow-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Icons/arrow-left.png -------------------------------------------------------------------------------- /src/Resources/Icons/arrow-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Icons/arrow-right.png -------------------------------------------------------------------------------- /src/Resources/Icons/arrow-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Icons/arrow-up.png -------------------------------------------------------------------------------- /src/Resources/Icons/zoom-in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Icons/zoom-in.png -------------------------------------------------------------------------------- /src/Resources/Icons/zoom-out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Icons/zoom-out.png -------------------------------------------------------------------------------- /src/Resources/Images/OnGuard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Images/OnGuard.jpg -------------------------------------------------------------------------------- /src/Resources/Images/OnGuardNoPictures.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Images/OnGuardNoPictures.jpg -------------------------------------------------------------------------------- /src/Resources/Samples/Street1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Samples/Street1.jpg -------------------------------------------------------------------------------- /src/Resources/Samples/Street2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Samples/Street2.jpg -------------------------------------------------------------------------------- /src/Resources/Samples/Street3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Samples/Street3.jpg -------------------------------------------------------------------------------- /src/Resources/Samples/Street4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Samples/Street4.jpg -------------------------------------------------------------------------------- /src/Resources/Samples/Street5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Samples/Street5.jpg -------------------------------------------------------------------------------- /src/Resources/Samples/Street6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Samples/Street6.jpg -------------------------------------------------------------------------------- /src/Resources/Samples/Street7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ken98045/On-Guard/74fe7f071a6a1afff81dec2dec69f0644ce3fa2f/src/Resources/Samples/Street7.jpg -------------------------------------------------------------------------------- /src/SafeParse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace OnGuardCore 8 | { 9 | // There are a LOT of cases where we are parsing values from various sources, primarily settings 10 | // in these cases we are getting strings and we need to parse them into the approriate type. 11 | // It is generally safe to leave them as the default (but not always which is why we log it) 12 | 13 | public static class SafeParse 14 | { 15 | public static object Parse(Type t, string str) 16 | { 17 | object o = null; 18 | 19 | try 20 | { 21 | if (!string.IsNullOrEmpty(str)) 22 | { 23 | 24 | if (t.BaseType.Name == "Enum") 25 | { 26 | o = 0; 27 | object ee = Enum.Parse(t, str); 28 | o = ee; 29 | } 30 | else 31 | { 32 | 33 | switch (t.Name) 34 | { 35 | case "Int32": 36 | o = 0; 37 | int ii = int.Parse(str); 38 | o = ii; 39 | break; 40 | 41 | case "Double": 42 | o = 0.0; 43 | double dd = double.Parse(str); 44 | o = dd; 45 | break; 46 | 47 | case "Boolean": 48 | o = false; 49 | object oo = bool.Parse(str); 50 | o = oo; 51 | break; 52 | 53 | case "Guid": 54 | o = Guid.Empty; 55 | Guid gg = Guid.Parse(str); 56 | o = gg; 57 | break; 58 | 59 | default: 60 | o = null; 61 | break; 62 | 63 | } 64 | } 65 | } 66 | else 67 | { 68 | 69 | if (t.BaseType.Name == "Enum") 70 | { 71 | o = 0; // a reasonable default? 72 | } 73 | else 74 | { 75 | 76 | switch (t.Name) 77 | { 78 | case "Int32": 79 | o = 0; 80 | break; 81 | 82 | case "Double": 83 | o = 0.0; 84 | break; 85 | 86 | case "Boolean": 87 | o = false; 88 | break; 89 | 90 | case "Guid": 91 | o = Guid.Empty; 92 | break; 93 | 94 | default: 95 | o = null; 96 | break; 97 | 98 | } 99 | } 100 | 101 | } 102 | } 103 | catch (Exception ex) 104 | { 105 | Dbg.Write(LogLevel.Error, "SafeParse - Unexpected exception: " + ex.Message); 106 | } 107 | 108 | return o; 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/Storage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.IO; 7 | using OnGuardCore.Src.Properties; 8 | using System.Windows.Forms; 9 | using Microsoft.Win32; 10 | using System.Drawing; 11 | 12 | namespace OnGuardCore 13 | { 14 | public class Storage 15 | { 16 | private static IStorage _xmlStore = new XMLStorage(); 17 | Storage() 18 | { 19 | 20 | } 21 | 22 | public static bool DoesDataDirectoryExist() 23 | { 24 | bool result = false; 25 | 26 | string path = Settings.Default.DataFileLocation; 27 | if (Directory.Exists(path)) 28 | { 29 | result = true; 30 | } 31 | return result; 32 | } 33 | 34 | public static bool DoesSettingsFileExist() 35 | { 36 | bool result = false; 37 | 38 | if (DoesDataDirectoryExist()) 39 | { 40 | string path = GetFilePath("OnGuardStorage.xml"); 41 | if (File.Exists(path)) 42 | { 43 | result=true; 44 | } 45 | } 46 | 47 | return result; 48 | } 49 | 50 | static public string GetFilePath(string fileName) 51 | { 52 | string path = Settings.Default.DataFileLocation; 53 | if (string.IsNullOrEmpty(path)) 54 | { 55 | using OnGuardDataDialog dlg = new (); 56 | if (DialogResult.OK == dlg.ShowDialog()) 57 | { 58 | path = dlg.FolderLocation; 59 | Settings.Default.DataFileLocation = path; 60 | Settings.Default.DatabaseFileLocation = dlg.DatabaseFolderLocation; 61 | Settings.Default.Save(); 62 | } 63 | else 64 | { 65 | MessageBox.Show("You must set a data file folder. The application will now exit", "Exiting!"); 66 | Application.Exit(); 67 | } 68 | } 69 | 70 | if (!Directory.Exists(path)) 71 | { 72 | Directory.CreateDirectory(path); 73 | } 74 | 75 | if (!string.IsNullOrEmpty(fileName)) 76 | { 77 | path = Path.Combine(path, fileName); 78 | } 79 | 80 | return path; 81 | } 82 | 83 | 84 | public static IStorage Instance 85 | { 86 | get 87 | { 88 | return _xmlStore; 89 | } 90 | } 91 | 92 | } 93 | 94 | 95 | } 96 | 97 | -------------------------------------------------------------------------------- /src/TimeTrigger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace OnGuardCore 9 | { 10 | public delegate void GuidDelegate(Guid id); 11 | public class TimeTrigger 12 | { 13 | static Dictionary _timers = new Dictionary(); 14 | public static event GuidDelegate OnTimeTriggered = delegate { }; 15 | 16 | // The trigger passed in is not a full date/time. 17 | // Rather, it is a time such as 4:46pm where the time might be today/tomorrow -- we ignore the year/month/day/seconds 18 | public static void AddTimer(DateTime trigger, Guid id) 19 | { 20 | DateTime now = DateTime.Now; 21 | 22 | // Get some easy comparison for the requested vs now. 23 | int totalNowMin = (now.Hour * 60) + now.Minute; 24 | int totalTriggerMin = (trigger.Hour * 60) + trigger.Minute; 25 | DateTime realTrigger = now; 26 | 27 | if (totalNowMin >= totalTriggerMin) 28 | { 29 | // we are dealing with tomorrow, not today 30 | realTrigger = new DateTime(now.Year, now.Month, now.Day, trigger.Hour, trigger.Minute, 0); 31 | realTrigger = realTrigger.AddDays(1); 32 | } 33 | else 34 | { 35 | realTrigger = new DateTime(now.Year, now.Month, now.Day, trigger.Hour, trigger.Minute, 0); // today 36 | } 37 | 38 | TimeSpan span = realTrigger - now; 39 | 40 | Timer timer = new Timer(OnTimer, id, span, TimeSpan.FromMilliseconds(-1)); 41 | _timers[id] = timer; 42 | 43 | } 44 | 45 | 46 | private static void OnTimer(object obj) 47 | { 48 | Guid id = (Guid)obj; 49 | OnTimeTriggered(id); 50 | _timers[id].Change(TimeSpan.FromDays(1), TimeSpan.FromMilliseconds(-1)); // reset for tomorrow 51 | } 52 | 53 | public static void Remove(Guid id) 54 | { 55 | if (_timers.ContainsKey(id)) 56 | { 57 | Timer t = _timers[id]; 58 | t.Dispose(); 59 | _timers.Remove(id); 60 | } 61 | 62 | } 63 | 64 | public static void ClearAll() 65 | { 66 | foreach (var timer in _timers.Values) 67 | { 68 | timer.Dispose(); 69 | } 70 | 71 | _timers.Clear(); 72 | } 73 | 74 | public static DateTime GetHourMinute(int hour, int minute) 75 | { 76 | DateTime newDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, hour, minute, 0); 77 | return newDate; 78 | } 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /src/TimerPlus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace OnGuardCore 4 | { 5 | 6 | public class TimerPlus : System.Timers.Timer 7 | { 8 | private DateTime m_dueTime; 9 | 10 | public TimerPlus() : base() 11 | { 12 | this.Elapsed += this.ElapsedAction; 13 | } 14 | 15 | protected new void Dispose() 16 | { 17 | this.Elapsed -= this.ElapsedAction; 18 | base.Dispose(); 19 | } 20 | 21 | public double TimeLeft 22 | { 23 | get 24 | { 25 | return (this.m_dueTime - DateTime.Now).TotalMilliseconds; 26 | } 27 | } 28 | 29 | public new void Start() 30 | { 31 | this.m_dueTime = DateTime.Now.AddMilliseconds(this.Interval); 32 | 33 | base.Start(); 34 | } 35 | 36 | private void ElapsedAction(object sender, System.Timers.ElapsedEventArgs e) 37 | { 38 | if (this.AutoReset) 39 | { 40 | this.m_dueTime = DateTime.Now.AddMilliseconds(this.Interval); 41 | } 42 | } 43 | } 44 | 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/WaitCursor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | 8 | namespace OnGuardCore 9 | { 10 | public class WaitCursor : IDisposable 11 | { 12 | Cursor m_cursorOld; 13 | bool _disposedValue = false; // To detect redundant call 14 | 15 | /// 16 | /// .cteur 17 | /// 18 | public WaitCursor() 19 | { 20 | m_cursorOld = Cursor.Current; 21 | Cursor.Current = Cursors.WaitCursor; 22 | } 23 | 24 | /// 25 | /// Dispose 26 | /// 27 | public void Dispose() 28 | { 29 | Dispose(true); 30 | GC.SuppressFinalize(this); 31 | } 32 | 33 | 34 | /// 35 | /// Dispose 36 | /// 37 | /// 38 | protected virtual void Dispose(bool disposing) 39 | { 40 | if (!_disposedValue) 41 | { 42 | Cursor.Current = m_cursorOld; 43 | Cursor.Position = Cursor.Position; // force update 44 | } 45 | _disposedValue = true; 46 | } 47 | 48 | } 49 | } 50 | --------------------------------------------------------------------------------