first commit
This commit is contained in:
@@ -0,0 +1,311 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
// Copyright (C) LibreHardwareMonitor and Contributors.
|
||||
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
|
||||
// All Rights Reserved.
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Drawing.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using LibreHardwareMonitor.Hardware;
|
||||
using LibreHardwareMonitor.Utilities;
|
||||
|
||||
namespace LibreHardwareMonitor.UI;
|
||||
|
||||
public class SensorNotifyIcon : IDisposable
|
||||
{
|
||||
private readonly UnitManager _unitManager;
|
||||
private readonly NotifyIconAdv _notifyIcon;
|
||||
private readonly Bitmap _bitmap;
|
||||
private readonly Graphics _graphics;
|
||||
private Color _color;
|
||||
private Color _darkColor;
|
||||
private Brush _brush;
|
||||
private Brush _darkBrush;
|
||||
private readonly Pen _pen;
|
||||
private readonly Font _font;
|
||||
private readonly Font _smallFont;
|
||||
|
||||
public SensorNotifyIcon(SystemTray sensorSystemTray, ISensor sensor, PersistentSettings settings, UnitManager unitManager)
|
||||
{
|
||||
_unitManager = unitManager;
|
||||
Sensor = sensor;
|
||||
_notifyIcon = new NotifyIconAdv();
|
||||
|
||||
Color defaultColor = Color.White;
|
||||
if (sensor.SensorType == SensorType.Load || sensor.SensorType == SensorType.Control || sensor.SensorType == SensorType.Level)
|
||||
defaultColor = Color.FromArgb(0xff, 0x70, 0x8c, 0xf1);
|
||||
|
||||
Color = settings.GetValue(new Identifier(sensor.Identifier, "traycolor").ToString(), defaultColor);
|
||||
|
||||
_pen = new Pen(Color.FromArgb(96, Color.Black));
|
||||
ContextMenuStrip contextMenuStrip = new ContextMenuStrip();
|
||||
ToolStripItem hideShowItem = new ToolStripMenuItem("Hide/Show");
|
||||
hideShowItem.Click += delegate
|
||||
{
|
||||
sensorSystemTray.SendHideShowCommand();
|
||||
};
|
||||
contextMenuStrip.Items.Add(hideShowItem);
|
||||
contextMenuStrip.Items.Add(new ToolStripSeparator());
|
||||
ToolStripItem removeItem = new ToolStripMenuItem("Remove Sensor");
|
||||
removeItem.Click += delegate
|
||||
{
|
||||
sensorSystemTray.Remove(Sensor);
|
||||
};
|
||||
contextMenuStrip.Items.Add(removeItem);
|
||||
ToolStripItem colorItem = new ToolStripMenuItem("Change Color...");
|
||||
colorItem.Click += delegate
|
||||
{
|
||||
ColorDialog dialog = new ColorDialog { Color = Color };
|
||||
if (dialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
Color = dialog.Color;
|
||||
settings.SetValue(new Identifier(sensor.Identifier,
|
||||
"traycolor").ToString(), Color);
|
||||
}
|
||||
};
|
||||
contextMenuStrip.Items.Add(colorItem);
|
||||
contextMenuStrip.Items.Add(new ToolStripSeparator());
|
||||
ToolStripItem exitItem = new ToolStripMenuItem("Exit");
|
||||
exitItem.Click += delegate
|
||||
{
|
||||
sensorSystemTray.SendExitCommand();
|
||||
};
|
||||
contextMenuStrip.Items.Add(exitItem);
|
||||
_notifyIcon.ContextMenuStrip = contextMenuStrip;
|
||||
_notifyIcon.DoubleClick += delegate
|
||||
{
|
||||
sensorSystemTray.SendHideShowCommand();
|
||||
};
|
||||
|
||||
// get the default dpi to create an icon with the correct size
|
||||
float dpiX, dpiY;
|
||||
using (Bitmap b = new Bitmap(1, 1, PixelFormat.Format32bppArgb))
|
||||
{
|
||||
dpiX = b.HorizontalResolution;
|
||||
dpiY = b.VerticalResolution;
|
||||
}
|
||||
|
||||
// adjust the size of the icon to current dpi (default is 16x16 at 96 dpi)
|
||||
int width = (int)Math.Round(16 * dpiX / 96);
|
||||
int height = (int)Math.Round(16 * dpiY / 96);
|
||||
|
||||
// make sure it does never get smaller than 16x16
|
||||
width = width < 16 ? 16 : width;
|
||||
height = height < 16 ? 16 : height;
|
||||
|
||||
// adjust the font size to the icon size
|
||||
FontFamily family = SystemFonts.MessageBoxFont.FontFamily;
|
||||
float baseSize;
|
||||
switch (family.Name)
|
||||
{
|
||||
case "Segoe UI": baseSize = 12; break;
|
||||
case "Tahoma": baseSize = 11; break;
|
||||
default: baseSize = 12; break;
|
||||
}
|
||||
|
||||
_font = new Font(family, baseSize * width / 16.0f, GraphicsUnit.Pixel);
|
||||
_smallFont = new Font(family, 0.75f * baseSize * width / 16.0f, GraphicsUnit.Pixel);
|
||||
|
||||
_bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
|
||||
_graphics = Graphics.FromImage(_bitmap);
|
||||
if (Environment.OSVersion.Version.Major > 5)
|
||||
{
|
||||
_graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
|
||||
_graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
}
|
||||
}
|
||||
|
||||
public ISensor Sensor { get; }
|
||||
|
||||
public Color Color
|
||||
{
|
||||
get { return _color; }
|
||||
set
|
||||
{
|
||||
_color = value;
|
||||
_darkColor = Color.FromArgb(255, _color.R / 3, _color.G / 3, _color.B / 3);
|
||||
Brush brush = _brush;
|
||||
_brush = new SolidBrush(_color);
|
||||
brush?.Dispose();
|
||||
Brush darkBrush = _darkBrush;
|
||||
_darkBrush = new SolidBrush(_darkColor);
|
||||
darkBrush?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Icon icon = _notifyIcon.Icon;
|
||||
_notifyIcon.Icon = null;
|
||||
icon?.Destroy();
|
||||
_notifyIcon.Dispose();
|
||||
|
||||
_brush?.Dispose();
|
||||
_darkBrush?.Dispose();
|
||||
_pen.Dispose();
|
||||
_graphics.Dispose();
|
||||
_bitmap.Dispose();
|
||||
_font.Dispose();
|
||||
_smallFont.Dispose();
|
||||
}
|
||||
|
||||
private string GetString()
|
||||
{
|
||||
if (!Sensor.Value.HasValue)
|
||||
return "-";
|
||||
|
||||
switch (Sensor.SensorType)
|
||||
{
|
||||
case SensorType.Temperature:
|
||||
return _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit ? $"{UnitManager.CelsiusToFahrenheit(Sensor.Value):F0}" : $"{Sensor.Value:F0}";
|
||||
case SensorType.TimeSpan:
|
||||
return $"{TimeSpan.FromSeconds(Sensor.Value.Value):g}";
|
||||
case SensorType.Clock:
|
||||
case SensorType.Fan:
|
||||
case SensorType.Flow:
|
||||
return $"{1e-3f * Sensor.Value:F1}";
|
||||
case SensorType.Voltage:
|
||||
case SensorType.Current:
|
||||
case SensorType.SmallData:
|
||||
case SensorType.Factor:
|
||||
case SensorType.Throughput:
|
||||
case SensorType.Conductivity:
|
||||
return $"{Sensor.Value:F1}";
|
||||
case SensorType.Control:
|
||||
case SensorType.Frequency:
|
||||
case SensorType.Level:
|
||||
case SensorType.Power:
|
||||
case SensorType.Data:
|
||||
case SensorType.Load:
|
||||
case SensorType.Energy:
|
||||
case SensorType.Noise:
|
||||
case SensorType.Humidity:
|
||||
return $"{Sensor.Value:F0}";
|
||||
default:
|
||||
return "-";
|
||||
}
|
||||
}
|
||||
|
||||
private Icon CreateTransparentIcon()
|
||||
{
|
||||
string text = GetString();
|
||||
int count = 0;
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
if ((text[i] >= '0' && text[i] <= '9') || text[i] == '-')
|
||||
count++;
|
||||
bool small = count > 2;
|
||||
|
||||
_graphics.Clear(Color.Black);
|
||||
Rectangle bounds = new Rectangle(Point.Empty, _bitmap.Size);
|
||||
TextRenderer.DrawText(_graphics, text, small ? _smallFont : _font,
|
||||
bounds, Color.White, Color.Black, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
|
||||
|
||||
BitmapData data = _bitmap.LockBits(
|
||||
new Rectangle(0, 0, _bitmap.Width, _bitmap.Height),
|
||||
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
||||
|
||||
IntPtr Scan0 = data.Scan0;
|
||||
|
||||
int numBytes = _bitmap.Width * _bitmap.Height * 4;
|
||||
byte[] bytes = new byte[numBytes];
|
||||
Marshal.Copy(Scan0, bytes, 0, numBytes);
|
||||
_bitmap.UnlockBits(data);
|
||||
|
||||
byte red, green, blue;
|
||||
for (int i = 0; i < bytes.Length; i += 4)
|
||||
{
|
||||
blue = bytes[i];
|
||||
green = bytes[i + 1];
|
||||
red = bytes[i + 2];
|
||||
|
||||
bytes[i] = _color.B;
|
||||
bytes[i + 1] = _color.G;
|
||||
bytes[i + 2] = _color.R;
|
||||
bytes[i + 3] = (byte)(0.3 * red + 0.59 * green + 0.11 * blue);
|
||||
}
|
||||
|
||||
return IconFactory.Create(bytes, _bitmap.Width, _bitmap.Height,
|
||||
PixelFormat.Format32bppArgb);
|
||||
}
|
||||
|
||||
private Icon CreatePercentageIcon()
|
||||
{
|
||||
try
|
||||
{
|
||||
_graphics.Clear(Color.Transparent);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
_graphics.Clear(Color.Black);
|
||||
}
|
||||
_graphics.FillRectangle(_darkBrush, 0.5f, -0.5f, _bitmap.Width - 2, _bitmap.Height);
|
||||
float value = Sensor.Value.GetValueOrDefault();
|
||||
float y = (float)(_bitmap.Height * 0.01f) * (100 - value);
|
||||
_graphics.FillRectangle(_brush, 0.5f, -0.5f + y, _bitmap.Width - 2, _bitmap.Height - y);
|
||||
_graphics.DrawRectangle(_pen, 1, 0, _bitmap.Width - 3, _bitmap.Height - 1);
|
||||
|
||||
return IconFactory.Create(_bitmap);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
Icon icon = _notifyIcon.Icon;
|
||||
|
||||
switch (Sensor.SensorType)
|
||||
{
|
||||
case SensorType.Load:
|
||||
case SensorType.Control:
|
||||
case SensorType.Level:
|
||||
_notifyIcon.Icon = CreatePercentageIcon();
|
||||
break;
|
||||
default:
|
||||
_notifyIcon.Icon = CreateTransparentIcon();
|
||||
break;
|
||||
}
|
||||
|
||||
icon?.Destroy();
|
||||
|
||||
string format = "";
|
||||
switch (Sensor.SensorType)
|
||||
{
|
||||
case SensorType.Voltage: format = "\n{0}: {1:F2} V"; break;
|
||||
case SensorType.Current: format = "\n{0}: {1:F2} A"; break;
|
||||
case SensorType.Clock: format = "\n{0}: {1:F0} MHz"; break;
|
||||
case SensorType.Load: format = "\n{0}: {1:F1} %"; break;
|
||||
case SensorType.Temperature: format = "\n{0}: {1:F1} °C"; break;
|
||||
case SensorType.Fan: format = "\n{0}: {1:F0} RPM"; break;
|
||||
case SensorType.Flow: format = "\n{0}: {1:F0} L/h"; break;
|
||||
case SensorType.Control: format = "\n{0}: {1:F1} %"; break;
|
||||
case SensorType.Level: format = "\n{0}: {1:F1} %"; break;
|
||||
case SensorType.Power: format = "\n{0}: {1:F0} W"; break;
|
||||
case SensorType.Data: format = "\n{0}: {1:F0} GB"; break;
|
||||
case SensorType.Factor: format = "\n{0}: {1:F3} GB"; break;
|
||||
case SensorType.Energy: format = "\n{0}: {0:F0} mWh"; break;
|
||||
case SensorType.Noise: format = "\n{0}: {0:F0} dBA"; break;
|
||||
case SensorType.Conductivity: format = "\n{0}: {0:F1} µS/cm"; break;
|
||||
case SensorType.Humidity: format = "\n{0}: {0:F0} %"; break;
|
||||
}
|
||||
|
||||
string formattedValue = string.Format(format, Sensor.Name, Sensor.Value);
|
||||
|
||||
if (Sensor.SensorType == SensorType.Temperature && _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit)
|
||||
{
|
||||
format = "\n{0}: {1:F1} °F";
|
||||
formattedValue = string.Format(format, Sensor.Name, UnitManager.CelsiusToFahrenheit(Sensor.Value));
|
||||
}
|
||||
|
||||
string hardwareName = Sensor.Hardware.Name;
|
||||
hardwareName = hardwareName.Substring(0, Math.Min(63 - formattedValue.Length, hardwareName.Length));
|
||||
string text = hardwareName + formattedValue;
|
||||
if (text.Length > 63)
|
||||
text = null;
|
||||
|
||||
_notifyIcon.Text = text;
|
||||
_notifyIcon.Visible = true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user