Initial commit: application ColorPicker (palette, pipette ecran, couleur de dossier)
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
*.exe
|
||||||
|
*.pdb
|
||||||
|
*.obj
|
||||||
45
LISEZMOI.txt
Normal file
45
LISEZMOI.txt
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
ColorPicker - Palette de couleurs & couleur de dossier
|
||||||
|
========================================================
|
||||||
|
|
||||||
|
UTILISATION
|
||||||
|
-----------
|
||||||
|
Aucune installation requise : lancez simplement ColorPicker.exe.
|
||||||
|
Compatible Windows 10 et 11, 32 et 64 bits (necessite le .NET Framework 4.8,
|
||||||
|
present par defaut sur ces versions de Windows).
|
||||||
|
|
||||||
|
FONCTIONNALITES
|
||||||
|
----------------
|
||||||
|
1. Palette de couleurs complete (a gauche) : cliquez sur une case pour la
|
||||||
|
selectionner.
|
||||||
|
|
||||||
|
2. Couleur personnalisee / en dehors de la palette :
|
||||||
|
- Bouton "Preleve une couleur a l'ecran" : le curseur se transforme en
|
||||||
|
pipette, deplacez-le n'importe ou sur l'ecran (meme en dehors de
|
||||||
|
l'application) et cliquez pour capturer la couleur exacte du pixel
|
||||||
|
survole. Echap pour annuler.
|
||||||
|
- Bouton "Couleur personnalisee..." : ouvre le selecteur Windows complet
|
||||||
|
(roue de couleurs / valeurs RVB ou TSL precises).
|
||||||
|
- Vous pouvez aussi taper directement un code hexadecimal dans le champ
|
||||||
|
prevu puis valider avec Entree ou le bouton "OK".
|
||||||
|
|
||||||
|
3. Codes en temps reel : le code hexadecimal (#RRGGBB) et le code RGB
|
||||||
|
(R, G, B) s'affichent et se mettent a jour instantanement. Chaque champ
|
||||||
|
a son propre bouton "Copier" pour coller le code dans PowerShell, cmd,
|
||||||
|
Word, Excel, ou tout autre logiciel.
|
||||||
|
|
||||||
|
4. Couleur d'un dossier Windows :
|
||||||
|
- "Parcourir..." pour choisir le dossier a colorer.
|
||||||
|
- "Appliquer la couleur au dossier" applique la couleur actuellement
|
||||||
|
selectionnee a l'icone du dossier (icone generee et un fichier
|
||||||
|
desktop.ini sont crees dans le dossier, en fichiers caches/systeme).
|
||||||
|
- "Restaurer la couleur par defaut" supprime ces fichiers et redonne au
|
||||||
|
dossier son icone Windows standard.
|
||||||
|
- Si l'icone ne se met pas a jour immediatement dans l'Explorateur,
|
||||||
|
fermez puis rouvrez la fenetre du dossier (ou appuyez sur F5).
|
||||||
|
|
||||||
|
RECOMPILER LE PROJET
|
||||||
|
---------------------
|
||||||
|
Le code source complet se trouve dans le dossier src\. Pour recompiler,
|
||||||
|
executez build.bat (utilise le compilateur C# fourni avec le
|
||||||
|
.NET Framework, deja present sur Windows - aucun outil supplementaire
|
||||||
|
n'est necessaire).
|
||||||
26
app.manifest
Normal file
26
app.manifest
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<assemblyIdentity version="1.0.0.0" name="ColorPicker.App"/>
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||||
|
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||||
|
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||||
|
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||||
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<windowsSettings>
|
||||||
|
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
|
||||||
|
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor, System</dpiAwareness>
|
||||||
|
</windowsSettings>
|
||||||
|
</application>
|
||||||
|
</assembly>
|
||||||
18
build.bat
Normal file
18
build.bat
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
set CSC="%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\csc.exe"
|
||||||
|
if not exist %CSC% set CSC="%WINDIR%\Microsoft.NET\Framework\v4.0.30319\csc.exe"
|
||||||
|
|
||||||
|
%CSC% /nologo /platform:anycpu /target:winexe /out:ColorPicker.exe /win32manifest:app.manifest ^
|
||||||
|
/reference:System.dll /reference:System.Core.dll /reference:System.Drawing.dll /reference:System.Windows.Forms.dll ^
|
||||||
|
src\Program.cs src\MainForm.cs src\Palette.cs src\ScreenColorPickerForm.cs src\MagnifierForm.cs src\FolderColorizer.cs src\IconWriter.cs
|
||||||
|
|
||||||
|
if %ERRORLEVEL% NEQ 0 (
|
||||||
|
echo.
|
||||||
|
echo *** Echec de la compilation ***
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Compilation reussie : ColorPicker.exe
|
||||||
|
endlocal
|
||||||
189
src/FolderColorizer.cs
Normal file
189
src/FolderColorizer.cs
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace ColorPickerApp
|
||||||
|
{
|
||||||
|
/// <summary>Applique ou restaure une icone de dossier coloree via desktop.ini (aucune API Windows
|
||||||
|
/// ne permet de "teinter" nativement l'icone systeme : on genere une icone de remplacement).</summary>
|
||||||
|
internal static class FolderColorizer
|
||||||
|
{
|
||||||
|
private const string IconFileName = ".colorpicker_folder.ico";
|
||||||
|
private const string BackupSuffix = ".colorpicker_backup";
|
||||||
|
|
||||||
|
[DllImport("shell32.dll")]
|
||||||
|
private static extern void SHChangeNotify(int wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2);
|
||||||
|
|
||||||
|
private const int SHCNE_ASSOCCHANGED = 0x08000000;
|
||||||
|
private const int SHCNF_IDLIST = 0x0000;
|
||||||
|
|
||||||
|
public static void ApplyColor(string folderPath, Color color)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(folderPath))
|
||||||
|
throw new DirectoryNotFoundException(folderPath);
|
||||||
|
|
||||||
|
string iconPath = Path.Combine(folderPath, IconFileName);
|
||||||
|
string desktopIniPath = Path.Combine(folderPath, "desktop.ini");
|
||||||
|
|
||||||
|
var images = new List<Bitmap>
|
||||||
|
{
|
||||||
|
DrawFolderIcon(color, 16),
|
||||||
|
DrawFolderIcon(color, 32),
|
||||||
|
DrawFolderIcon(color, 48),
|
||||||
|
DrawFolderIcon(color, 256)
|
||||||
|
};
|
||||||
|
|
||||||
|
ClearReadOnlyAndHidden(iconPath);
|
||||||
|
IconWriter.WriteIcon(iconPath, images);
|
||||||
|
foreach (var b in images) b.Dispose();
|
||||||
|
File.SetAttributes(iconPath, FileAttributes.Hidden | FileAttributes.System);
|
||||||
|
|
||||||
|
// Conserver un desktop.ini existant (personnalise par l'utilisateur) si present et non genere par nous
|
||||||
|
if (File.Exists(desktopIniPath) && !IsOurDesktopIni(desktopIniPath))
|
||||||
|
{
|
||||||
|
File.Copy(desktopIniPath, desktopIniPath + BackupSuffix, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearReadOnlyAndHidden(desktopIniPath);
|
||||||
|
File.WriteAllText(desktopIniPath,
|
||||||
|
"[.ShellClassInfo]" + Environment.NewLine +
|
||||||
|
"IconResource=" + IconFileName + ",0" + Environment.NewLine +
|
||||||
|
"IconFile=" + IconFileName + Environment.NewLine +
|
||||||
|
"IconIndex=0" + Environment.NewLine +
|
||||||
|
"; genere par ColorPicker" + Environment.NewLine);
|
||||||
|
File.SetAttributes(desktopIniPath, FileAttributes.Hidden | FileAttributes.System);
|
||||||
|
|
||||||
|
var dirInfo = new DirectoryInfo(folderPath);
|
||||||
|
dirInfo.Attributes |= FileAttributes.ReadOnly;
|
||||||
|
|
||||||
|
NotifyShell(folderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RestoreDefault(string folderPath)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(folderPath))
|
||||||
|
throw new DirectoryNotFoundException(folderPath);
|
||||||
|
|
||||||
|
string iconPath = Path.Combine(folderPath, IconFileName);
|
||||||
|
string desktopIniPath = Path.Combine(folderPath, "desktop.ini");
|
||||||
|
string backupPath = desktopIniPath + BackupSuffix;
|
||||||
|
|
||||||
|
if (File.Exists(iconPath))
|
||||||
|
{
|
||||||
|
ClearReadOnlyAndHidden(iconPath);
|
||||||
|
File.Delete(iconPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(desktopIniPath) && IsOurDesktopIni(desktopIniPath))
|
||||||
|
{
|
||||||
|
ClearReadOnlyAndHidden(desktopIniPath);
|
||||||
|
File.Delete(desktopIniPath);
|
||||||
|
|
||||||
|
if (File.Exists(backupPath))
|
||||||
|
{
|
||||||
|
File.Copy(backupPath, desktopIniPath, true);
|
||||||
|
File.SetAttributes(desktopIniPath, FileAttributes.Hidden | FileAttributes.System);
|
||||||
|
File.Delete(backupPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var dirInfo = new DirectoryInfo(folderPath);
|
||||||
|
dirInfo.Attributes &= ~FileAttributes.ReadOnly;
|
||||||
|
|
||||||
|
NotifyShell(folderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasCustomColor(string folderPath)
|
||||||
|
{
|
||||||
|
string desktopIniPath = Path.Combine(folderPath, "desktop.ini");
|
||||||
|
return File.Exists(desktopIniPath) && IsOurDesktopIni(desktopIniPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsOurDesktopIni(string desktopIniPath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string content = File.ReadAllText(desktopIniPath);
|
||||||
|
return content.IndexOf(IconFileName, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ClearReadOnlyAndHidden(string filePath)
|
||||||
|
{
|
||||||
|
if (File.Exists(filePath))
|
||||||
|
{
|
||||||
|
File.SetAttributes(filePath, FileAttributes.Normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void NotifyShell(string folderPath)
|
||||||
|
{
|
||||||
|
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, IntPtr.Zero, IntPtr.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Bitmap DrawFolderIcon(Color color, int size)
|
||||||
|
{
|
||||||
|
var bmp = new Bitmap(size, size, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
||||||
|
using (var g = Graphics.FromImage(bmp))
|
||||||
|
{
|
||||||
|
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||||
|
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||||
|
g.Clear(Color.Transparent);
|
||||||
|
|
||||||
|
float w = size, h = size;
|
||||||
|
Color body = color;
|
||||||
|
Color tab = ControlPaint.Light(color, 0.15f);
|
||||||
|
Color outline = ControlPaint.Dark(color, 0.25f);
|
||||||
|
|
||||||
|
float tabW = w * 0.45f, tabH = h * 0.18f;
|
||||||
|
float tabX = w * 0.06f, tabY = h * 0.18f;
|
||||||
|
var tabRect = new RectangleF(tabX, tabY, tabW, tabH);
|
||||||
|
|
||||||
|
float bodyX = w * 0.06f, bodyY = h * 0.30f;
|
||||||
|
float bodyW = w * 0.88f, bodyH = h * 0.56f;
|
||||||
|
var bodyRect = new RectangleF(bodyX, bodyY, bodyW, bodyH);
|
||||||
|
|
||||||
|
float radius = Math.Max(1f, size * 0.06f);
|
||||||
|
|
||||||
|
using (var tabPath = RoundedRect(tabRect, radius))
|
||||||
|
using (var tabBrush = new SolidBrush(tab))
|
||||||
|
{
|
||||||
|
g.FillPath(tabBrush, tabPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var bodyPath = RoundedRect(bodyRect, radius))
|
||||||
|
{
|
||||||
|
using (var bodyBrush = new LinearGradientBrush(bodyRect, ControlPaint.Light(body, 0.05f), ControlPaint.Dark(body, 0.05f), LinearGradientMode.Vertical))
|
||||||
|
{
|
||||||
|
g.FillPath(bodyBrush, bodyPath);
|
||||||
|
}
|
||||||
|
using (var pen = new Pen(outline, Math.Max(1f, size / 32f)))
|
||||||
|
{
|
||||||
|
g.DrawPath(pen, bodyPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GraphicsPath RoundedRect(RectangleF rect, float radius)
|
||||||
|
{
|
||||||
|
var path = new GraphicsPath();
|
||||||
|
float d = radius * 2;
|
||||||
|
path.AddArc(rect.X, rect.Y, d, d, 180, 90);
|
||||||
|
path.AddArc(rect.Right - d, rect.Y, d, d, 270, 90);
|
||||||
|
path.AddArc(rect.Right - d, rect.Bottom - d, d, d, 0, 90);
|
||||||
|
path.AddArc(rect.X, rect.Bottom - d, d, d, 90, 90);
|
||||||
|
path.CloseFigure();
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/IconWriter.cs
Normal file
52
src/IconWriter.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace ColorPickerApp
|
||||||
|
{
|
||||||
|
/// <summary>Ecrit un fichier .ico multi-resolution a partir de bitmaps PNG (format ICO "Vista").</summary>
|
||||||
|
internal static class IconWriter
|
||||||
|
{
|
||||||
|
public static void WriteIcon(string path, IList<Bitmap> images)
|
||||||
|
{
|
||||||
|
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
|
||||||
|
using (var writer = new BinaryWriter(fs))
|
||||||
|
{
|
||||||
|
writer.Write((ushort)0); // reserved
|
||||||
|
writer.Write((ushort)1); // type = icon
|
||||||
|
writer.Write((ushort)images.Count);
|
||||||
|
|
||||||
|
var pngBlocks = new byte[images.Count][];
|
||||||
|
for (int i = 0; i < images.Count; i++)
|
||||||
|
{
|
||||||
|
using (var ms = new MemoryStream())
|
||||||
|
{
|
||||||
|
images[i].Save(ms, ImageFormat.Png);
|
||||||
|
pngBlocks[i] = ms.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset = 6 + images.Count * 16;
|
||||||
|
for (int i = 0; i < images.Count; i++)
|
||||||
|
{
|
||||||
|
int size = images[i].Width; // carre
|
||||||
|
writer.Write((byte)(size >= 256 ? 0 : size));
|
||||||
|
writer.Write((byte)(size >= 256 ? 0 : size));
|
||||||
|
writer.Write((byte)0); // palette
|
||||||
|
writer.Write((byte)0); // reserved
|
||||||
|
writer.Write((ushort)1); // planes
|
||||||
|
writer.Write((ushort)32); // bitcount
|
||||||
|
writer.Write((uint)pngBlocks[i].Length);
|
||||||
|
writer.Write((uint)offset);
|
||||||
|
offset += pngBlocks[i].Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < images.Count; i++)
|
||||||
|
{
|
||||||
|
writer.Write(pngBlocks[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
69
src/MagnifierForm.cs
Normal file
69
src/MagnifierForm.cs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace ColorPickerApp
|
||||||
|
{
|
||||||
|
/// <summary>Petite fenetre flottante qui suit le curseur et affiche la couleur survolee.</summary>
|
||||||
|
internal sealed class MagnifierForm : Form
|
||||||
|
{
|
||||||
|
private readonly Panel _swatch;
|
||||||
|
private readonly Label _label;
|
||||||
|
|
||||||
|
public MagnifierForm()
|
||||||
|
{
|
||||||
|
FormBorderStyle = FormBorderStyle.None;
|
||||||
|
ShowInTaskbar = false;
|
||||||
|
StartPosition = FormStartPosition.Manual;
|
||||||
|
TopMost = true;
|
||||||
|
Size = new Size(150, 44);
|
||||||
|
BackColor = Color.FromArgb(32, 32, 32);
|
||||||
|
DoubleBuffered = true;
|
||||||
|
|
||||||
|
_swatch = new Panel { Location = new Point(6, 6), Size = new Size(32, 32), BorderStyle = BorderStyle.FixedSingle };
|
||||||
|
_label = new Label
|
||||||
|
{
|
||||||
|
Location = new Point(44, 6),
|
||||||
|
Size = new Size(100, 32),
|
||||||
|
ForeColor = Color.White,
|
||||||
|
Font = new Font("Consolas", 9F),
|
||||||
|
TextAlign = System.Drawing.ContentAlignment.MiddleLeft
|
||||||
|
};
|
||||||
|
|
||||||
|
Controls.Add(_swatch);
|
||||||
|
Controls.Add(_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateDisplay(Point screenPoint, Color color)
|
||||||
|
{
|
||||||
|
_swatch.BackColor = color;
|
||||||
|
_label.Text = string.Format("#{0:X2}{1:X2}{2:X2}", color.R, color.G, color.B);
|
||||||
|
|
||||||
|
int x = screenPoint.X + 20;
|
||||||
|
int y = screenPoint.Y + 20;
|
||||||
|
|
||||||
|
var screen = Screen.FromPoint(screenPoint).Bounds;
|
||||||
|
if (x + Width > screen.Right) x = screenPoint.X - Width - 10;
|
||||||
|
if (y + Height > screen.Bottom) y = screenPoint.Y - Height - 10;
|
||||||
|
|
||||||
|
Location = new Point(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool ShowWithoutActivation
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override CreateParams CreateParams
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
const int WS_EX_NOACTIVATE = 0x08000000;
|
||||||
|
const int WS_EX_TOOLWINDOW = 0x00000080;
|
||||||
|
CreateParams cp = base.CreateParams;
|
||||||
|
cp.ExStyle |= WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW;
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
302
src/MainForm.cs
Normal file
302
src/MainForm.cs
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace ColorPickerApp
|
||||||
|
{
|
||||||
|
internal sealed class MainForm : Form
|
||||||
|
{
|
||||||
|
private FlowLayoutPanel _paletteFlow;
|
||||||
|
private Panel _preview;
|
||||||
|
private TextBox _hexBox;
|
||||||
|
private TextBox _rgbBox;
|
||||||
|
private TextBox _folderPathBox;
|
||||||
|
private Label _statusLabel;
|
||||||
|
private Color _currentColor = Color.FromArgb(0, 120, 215);
|
||||||
|
|
||||||
|
public MainForm()
|
||||||
|
{
|
||||||
|
BuildUi();
|
||||||
|
PopulatePalette();
|
||||||
|
SetCurrentColor(_currentColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildUi()
|
||||||
|
{
|
||||||
|
Text = "ColorPicker - Palette & Couleur de dossier";
|
||||||
|
StartPosition = FormStartPosition.CenterScreen;
|
||||||
|
ClientSize = new Size(760, 640);
|
||||||
|
MinimumSize = new Size(700, 600);
|
||||||
|
Font = new Font("Segoe UI", 9F);
|
||||||
|
|
||||||
|
// ---- Palette (gauche) ----
|
||||||
|
var paletteLabel = new Label
|
||||||
|
{
|
||||||
|
Text = "Palette de couleurs",
|
||||||
|
Location = new Point(16, 12),
|
||||||
|
AutoSize = true,
|
||||||
|
Font = new Font(Font, FontStyle.Bold)
|
||||||
|
};
|
||||||
|
|
||||||
|
_paletteFlow = new FlowLayoutPanel
|
||||||
|
{
|
||||||
|
Location = new Point(16, 36),
|
||||||
|
Size = new Size(400, 420),
|
||||||
|
AutoScroll = true,
|
||||||
|
BorderStyle = BorderStyle.FixedSingle,
|
||||||
|
BackColor = Color.White,
|
||||||
|
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Bottom
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---- Panneau droit : couleur courante ----
|
||||||
|
var rightX = 432;
|
||||||
|
|
||||||
|
var previewLabel = new Label { Text = "Couleur actuelle", Location = new Point(rightX, 12), AutoSize = true, Font = new Font(Font, FontStyle.Bold) };
|
||||||
|
|
||||||
|
_preview = new Panel
|
||||||
|
{
|
||||||
|
Location = new Point(rightX, 36),
|
||||||
|
Size = new Size(312, 80),
|
||||||
|
BorderStyle = BorderStyle.FixedSingle
|
||||||
|
};
|
||||||
|
|
||||||
|
var hexLabel = new Label { Text = "Code hexadécimal :", Location = new Point(rightX, 132), AutoSize = true };
|
||||||
|
_hexBox = new TextBox { Location = new Point(rightX, 152), Size = new Size(150, 24), Font = new Font("Consolas", 10F), MaxLength = 7 };
|
||||||
|
var hexCopyBtn = new Button { Text = "Copier", Location = new Point(rightX + 158, 151), Size = new Size(80, 26) };
|
||||||
|
var hexApplyBtn = new Button { Text = "OK", Location = new Point(rightX + 242, 151), Size = new Size(70, 26) };
|
||||||
|
|
||||||
|
var rgbLabel = new Label { Text = "Code RGB :", Location = new Point(rightX, 190), AutoSize = true };
|
||||||
|
_rgbBox = new TextBox { Location = new Point(rightX, 210), Size = new Size(150, 24), Font = new Font("Consolas", 10F), ReadOnly = true };
|
||||||
|
var rgbCopyBtn = new Button { Text = "Copier", Location = new Point(rightX + 158, 209), Size = new Size(80, 26) };
|
||||||
|
|
||||||
|
var eyedropperBtn = new Button
|
||||||
|
{
|
||||||
|
Text = "Prélever une couleur à l'écran",
|
||||||
|
Location = new Point(rightX, 254),
|
||||||
|
Size = new Size(312, 32)
|
||||||
|
};
|
||||||
|
|
||||||
|
var customColorBtn = new Button
|
||||||
|
{
|
||||||
|
Text = "Couleur personnalisée...",
|
||||||
|
Location = new Point(rightX, 292),
|
||||||
|
Size = new Size(312, 32)
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---- Groupe couleur de dossier ----
|
||||||
|
var folderGroup = new GroupBox
|
||||||
|
{
|
||||||
|
Text = "Couleur d'un dossier de l'explorateur",
|
||||||
|
Location = new Point(16, 468),
|
||||||
|
Size = new Size(728, 140),
|
||||||
|
Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom
|
||||||
|
};
|
||||||
|
|
||||||
|
_folderPathBox = new TextBox
|
||||||
|
{
|
||||||
|
Location = new Point(12, 28),
|
||||||
|
Size = new Size(500, 24),
|
||||||
|
ReadOnly = true,
|
||||||
|
Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top
|
||||||
|
};
|
||||||
|
var browseBtn = new Button { Text = "Parcourir...", Location = new Point(520, 27), Size = new Size(100, 26), Anchor = AnchorStyles.Right | AnchorStyles.Top };
|
||||||
|
var refreshHintLabel = new Label
|
||||||
|
{
|
||||||
|
Text = "Astuce : si l'icône ne change pas immédiatement, fermez/rouvrez l'explorateur du dossier.",
|
||||||
|
Location = new Point(12, 58),
|
||||||
|
AutoSize = true,
|
||||||
|
ForeColor = Color.DimGray
|
||||||
|
};
|
||||||
|
|
||||||
|
var applyFolderBtn = new Button { Text = "Appliquer la couleur au dossier", Location = new Point(12, 88), Size = new Size(220, 32) };
|
||||||
|
var restoreFolderBtn = new Button { Text = "Restaurer la couleur par défaut", Location = new Point(240, 88), Size = new Size(220, 32) };
|
||||||
|
|
||||||
|
_statusLabel = new Label { Location = new Point(472, 92), Size = new Size(240, 24), ForeColor = Color.DarkGreen, Anchor = AnchorStyles.Right | AnchorStyles.Bottom };
|
||||||
|
|
||||||
|
folderGroup.Controls.Add(_folderPathBox);
|
||||||
|
folderGroup.Controls.Add(browseBtn);
|
||||||
|
folderGroup.Controls.Add(refreshHintLabel);
|
||||||
|
folderGroup.Controls.Add(applyFolderBtn);
|
||||||
|
folderGroup.Controls.Add(restoreFolderBtn);
|
||||||
|
folderGroup.Controls.Add(_statusLabel);
|
||||||
|
|
||||||
|
Controls.Add(paletteLabel);
|
||||||
|
Controls.Add(_paletteFlow);
|
||||||
|
Controls.Add(previewLabel);
|
||||||
|
Controls.Add(_preview);
|
||||||
|
Controls.Add(hexLabel);
|
||||||
|
Controls.Add(_hexBox);
|
||||||
|
Controls.Add(hexCopyBtn);
|
||||||
|
Controls.Add(hexApplyBtn);
|
||||||
|
Controls.Add(rgbLabel);
|
||||||
|
Controls.Add(_rgbBox);
|
||||||
|
Controls.Add(rgbCopyBtn);
|
||||||
|
Controls.Add(eyedropperBtn);
|
||||||
|
Controls.Add(customColorBtn);
|
||||||
|
Controls.Add(folderGroup);
|
||||||
|
|
||||||
|
// ---- Evenements ----
|
||||||
|
hexCopyBtn.Click += (s, e) => CopyToClipboard(_hexBox.Text);
|
||||||
|
rgbCopyBtn.Click += (s, e) => CopyToClipboard(_rgbBox.Text);
|
||||||
|
hexApplyBtn.Click += (s, e) => TryApplyHexInput();
|
||||||
|
_hexBox.KeyDown += (s, e) => { if (e.KeyCode == Keys.Enter) { TryApplyHexInput(); e.SuppressKeyPress = true; } };
|
||||||
|
|
||||||
|
eyedropperBtn.Click += (s, e) => LaunchEyedropper();
|
||||||
|
customColorBtn.Click += (s, e) => LaunchCustomColorDialog();
|
||||||
|
|
||||||
|
browseBtn.Click += (s, e) => BrowseFolder();
|
||||||
|
applyFolderBtn.Click += (s, e) => ApplyFolderColor();
|
||||||
|
restoreFolderBtn.Click += (s, e) => RestoreFolderColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PopulatePalette()
|
||||||
|
{
|
||||||
|
foreach (var color in Palette.Generate())
|
||||||
|
{
|
||||||
|
var swatch = new Panel
|
||||||
|
{
|
||||||
|
Size = new Size(26, 26),
|
||||||
|
Margin = new Padding(2),
|
||||||
|
BackColor = color,
|
||||||
|
BorderStyle = BorderStyle.FixedSingle,
|
||||||
|
Cursor = Cursors.Hand,
|
||||||
|
Tag = color
|
||||||
|
};
|
||||||
|
swatch.Click += (s, e) => SetCurrentColor((Color)((Panel)s).Tag);
|
||||||
|
_paletteFlow.Controls.Add(swatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetCurrentColor(Color color)
|
||||||
|
{
|
||||||
|
_currentColor = color;
|
||||||
|
_preview.BackColor = color;
|
||||||
|
|
||||||
|
_hexBox.Text = string.Format("#{0:X2}{1:X2}{2:X2}", color.R, color.G, color.B);
|
||||||
|
_rgbBox.Text = string.Format("{0}, {1}, {2}", color.R, color.G, color.B);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TryApplyHexInput()
|
||||||
|
{
|
||||||
|
string text = _hexBox.Text.Trim();
|
||||||
|
if (!text.StartsWith("#")) text = "#" + text;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (text.Length != 7) throw new FormatException();
|
||||||
|
int r = Convert.ToInt32(text.Substring(1, 2), 16);
|
||||||
|
int g = Convert.ToInt32(text.Substring(3, 2), 16);
|
||||||
|
int b = Convert.ToInt32(text.Substring(5, 2), 16);
|
||||||
|
SetCurrentColor(Color.FromArgb(r, g, b));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
MessageBox.Show(this, "Code hexadécimal invalide. Format attendu : #RRGGBB", "Erreur",
|
||||||
|
MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||||
|
SetCurrentColor(_currentColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CopyToClipboard(string text)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(text)) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Clipboard.SetText(text);
|
||||||
|
ShowStatus("Copié : " + text, false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ShowStatus("Erreur copie : " + ex.Message, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LaunchEyedropper()
|
||||||
|
{
|
||||||
|
Hide();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var picker = new ScreenColorPickerForm())
|
||||||
|
{
|
||||||
|
picker.ShowDialog();
|
||||||
|
if (picker.PickedColor != Color.Empty)
|
||||||
|
{
|
||||||
|
SetCurrentColor(picker.PickedColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Show();
|
||||||
|
Activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LaunchCustomColorDialog()
|
||||||
|
{
|
||||||
|
using (var dlg = new ColorDialog { FullOpen = true, Color = _currentColor, AnyColor = true })
|
||||||
|
{
|
||||||
|
if (dlg.ShowDialog(this) == DialogResult.OK)
|
||||||
|
{
|
||||||
|
SetCurrentColor(dlg.Color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BrowseFolder()
|
||||||
|
{
|
||||||
|
using (var dlg = new FolderBrowserDialog { Description = "Choisir le dossier à colorer" })
|
||||||
|
{
|
||||||
|
if (dlg.ShowDialog(this) == DialogResult.OK)
|
||||||
|
{
|
||||||
|
_folderPathBox.Text = dlg.SelectedPath;
|
||||||
|
ShowStatus("", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyFolderColor()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_folderPathBox.Text))
|
||||||
|
{
|
||||||
|
ShowStatus("Sélectionnez d'abord un dossier.", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FolderColorizer.ApplyColor(_folderPathBox.Text, _currentColor);
|
||||||
|
ShowStatus("Couleur appliquée au dossier.", false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ShowStatus("Échec : " + ex.Message, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RestoreFolderColor()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_folderPathBox.Text))
|
||||||
|
{
|
||||||
|
ShowStatus("Sélectionnez d'abord un dossier.", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FolderColorizer.RestoreDefault(_folderPathBox.Text);
|
||||||
|
ShowStatus("Icône par défaut restaurée.", false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ShowStatus("Échec : " + ex.Message, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowStatus(string message, bool isError)
|
||||||
|
{
|
||||||
|
_statusLabel.Text = message;
|
||||||
|
_statusLabel.ForeColor = isError ? Color.Firebrick : Color.DarkGreen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
62
src/Palette.cs
Normal file
62
src/Palette.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace ColorPickerApp
|
||||||
|
{
|
||||||
|
/// <summary>Genere une palette complete (teintes x nuances + niveaux de gris).</summary>
|
||||||
|
internal static class Palette
|
||||||
|
{
|
||||||
|
public static List<Color> Generate()
|
||||||
|
{
|
||||||
|
var colors = new List<Color>();
|
||||||
|
|
||||||
|
const int hueSteps = 12;
|
||||||
|
const int shadeSteps = 8;
|
||||||
|
|
||||||
|
for (int s = 0; s < shadeSteps; s++)
|
||||||
|
{
|
||||||
|
double lightness = 0.90 - (s * (0.80 / (shadeSteps - 1)));
|
||||||
|
for (int h = 0; h < hueSteps; h++)
|
||||||
|
{
|
||||||
|
double hue = (360.0 / hueSteps) * h;
|
||||||
|
colors.Add(FromHsl(hue, 0.75, lightness));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int grayCount = 12;
|
||||||
|
for (int g = 0; g < grayCount; g++)
|
||||||
|
{
|
||||||
|
int v = (int)Math.Round(255.0 * g / (grayCount - 1));
|
||||||
|
colors.Add(Color.FromArgb(v, v, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
return colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Color FromHsl(double h, double s, double l)
|
||||||
|
{
|
||||||
|
double c = (1 - Math.Abs(2 * l - 1)) * s;
|
||||||
|
double x = c * (1 - Math.Abs((h / 60.0) % 2 - 1));
|
||||||
|
double m = l - c / 2;
|
||||||
|
|
||||||
|
double r1, g1, b1;
|
||||||
|
if (h < 60) { r1 = c; g1 = x; b1 = 0; }
|
||||||
|
else if (h < 120) { r1 = x; g1 = c; b1 = 0; }
|
||||||
|
else if (h < 180) { r1 = 0; g1 = c; b1 = x; }
|
||||||
|
else if (h < 240) { r1 = 0; g1 = x; b1 = c; }
|
||||||
|
else if (h < 300) { r1 = x; g1 = 0; b1 = c; }
|
||||||
|
else { r1 = c; g1 = 0; b1 = x; }
|
||||||
|
|
||||||
|
int r = (int)Math.Round((r1 + m) * 255);
|
||||||
|
int g = (int)Math.Round((g1 + m) * 255);
|
||||||
|
int b = (int)Math.Round((b1 + m) * 255);
|
||||||
|
|
||||||
|
r = Math.Max(0, Math.Min(255, r));
|
||||||
|
g = Math.Max(0, Math.Min(255, g));
|
||||||
|
b = Math.Max(0, Math.Min(255, b));
|
||||||
|
|
||||||
|
return Color.FromArgb(r, g, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/Program.cs
Normal file
16
src/Program.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace ColorPickerApp
|
||||||
|
{
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
[STAThread]
|
||||||
|
private static void Main()
|
||||||
|
{
|
||||||
|
Application.EnableVisualStyles();
|
||||||
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
|
Application.Run(new MainForm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
94
src/ScreenColorPickerForm.cs
Normal file
94
src/ScreenColorPickerForm.cs
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace ColorPickerApp
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Superpose une fenetre transparente plein ecran (tous moniteurs) permettant
|
||||||
|
/// de capturer la couleur de n'importe quel pixel affiche a l'ecran.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class ScreenColorPickerForm : Form
|
||||||
|
{
|
||||||
|
private readonly Timer _timer;
|
||||||
|
private readonly MagnifierForm _magnifier;
|
||||||
|
private Color _hoverColor = Color.White;
|
||||||
|
private Point _lastScreenPoint;
|
||||||
|
|
||||||
|
public Color PickedColor { get; private set; }
|
||||||
|
|
||||||
|
public ScreenColorPickerForm()
|
||||||
|
{
|
||||||
|
FormBorderStyle = FormBorderStyle.None;
|
||||||
|
ShowInTaskbar = false;
|
||||||
|
StartPosition = FormStartPosition.Manual;
|
||||||
|
TopMost = true;
|
||||||
|
BackColor = Color.Black;
|
||||||
|
Opacity = 0.01; // fenetre quasi invisible, sert uniquement a capter la souris
|
||||||
|
Cursor = Cursors.Cross;
|
||||||
|
DoubleBuffered = true;
|
||||||
|
KeyPreview = true;
|
||||||
|
|
||||||
|
Bounds = SystemInformation.VirtualScreen;
|
||||||
|
|
||||||
|
_magnifier = new MagnifierForm();
|
||||||
|
|
||||||
|
_timer = new Timer { Interval = 40 };
|
||||||
|
_timer.Tick += (s, e) => UpdateHover();
|
||||||
|
|
||||||
|
MouseClick += OnMouseClick;
|
||||||
|
KeyDown += (s, e) => { if (e.KeyCode == Keys.Escape) { PickedColor = Color.Empty; Close(); } };
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnShown(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnShown(e);
|
||||||
|
_magnifier.Show(this);
|
||||||
|
_timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFormClosed(FormClosedEventArgs e)
|
||||||
|
{
|
||||||
|
_timer.Stop();
|
||||||
|
_magnifier.Close();
|
||||||
|
base.OnFormClosed(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateHover()
|
||||||
|
{
|
||||||
|
_lastScreenPoint = Cursor.Position;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var bmp = new Bitmap(1, 1, PixelFormat.Format32bppArgb))
|
||||||
|
{
|
||||||
|
using (var g = Graphics.FromImage(bmp))
|
||||||
|
{
|
||||||
|
g.CopyFromScreen(_lastScreenPoint, Point.Empty, new Size(1, 1));
|
||||||
|
}
|
||||||
|
_hoverColor = bmp.GetPixel(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignore capture errors (ex: DPI change) et garder la derniere couleur connue
|
||||||
|
}
|
||||||
|
|
||||||
|
_magnifier.UpdateDisplay(_lastScreenPoint, _hoverColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMouseClick(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Button == MouseButtons.Left)
|
||||||
|
{
|
||||||
|
PickedColor = _hoverColor;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PickedColor = Color.Empty;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
tests/IconPreview.cs
Normal file
34
tests/IconPreview.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace ColorPickerApp
|
||||||
|
{
|
||||||
|
internal static class IconPreview
|
||||||
|
{
|
||||||
|
private static void Main(string[] args)
|
||||||
|
{
|
||||||
|
string dir = Path.Combine(Path.GetTempPath(), "cp_preview");
|
||||||
|
Directory.CreateDirectory(dir);
|
||||||
|
FolderColorizer.ApplyColor(dir, Color.FromArgb(220, 40, 60));
|
||||||
|
|
||||||
|
byte[] icoBytes = File.ReadAllBytes(Path.Combine(dir, ".colorpicker_folder.ico"));
|
||||||
|
int count = System.BitConverter.ToUInt16(icoBytes, 4);
|
||||||
|
// trouver l'entree 256x256 (largeur stockee = 0) avec le plus grand bytesInRes
|
||||||
|
int bestOffset = -1, bestSize = -1, bestLen = 0;
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
int entryOffset = 6 + i * 16;
|
||||||
|
int w = icoBytes[entryOffset];
|
||||||
|
int len = System.BitConverter.ToInt32(icoBytes, entryOffset + 8);
|
||||||
|
int off = System.BitConverter.ToInt32(icoBytes, entryOffset + 12);
|
||||||
|
if (w == 0 && len > bestLen) { bestLen = len; bestOffset = off; bestSize = w; }
|
||||||
|
}
|
||||||
|
var pngBytes = new byte[bestLen];
|
||||||
|
System.Array.Copy(icoBytes, bestOffset, pngBytes, 0, bestLen);
|
||||||
|
File.WriteAllBytes(Path.Combine(Path.GetTempPath(), "cp_icon_preview.png"), pngBytes);
|
||||||
|
|
||||||
|
FolderColorizer.RestoreDefault(dir);
|
||||||
|
Directory.Delete(dir, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
tests/TestHarness.cs
Normal file
46
tests/TestHarness.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace ColorPickerApp
|
||||||
|
{
|
||||||
|
internal static class TestHarness
|
||||||
|
{
|
||||||
|
private static void Main(string[] args)
|
||||||
|
{
|
||||||
|
string testDir = Path.Combine(Path.GetTempPath(), "cp_test_" + Guid.NewGuid().ToString("N").Substring(0, 8));
|
||||||
|
Directory.CreateDirectory(testDir);
|
||||||
|
Console.WriteLine("Dossier de test: " + testDir);
|
||||||
|
|
||||||
|
FolderColorizer.ApplyColor(testDir, Color.FromArgb(220, 40, 60));
|
||||||
|
Console.WriteLine("Apres ApplyColor:");
|
||||||
|
foreach (var f in Directory.GetFiles(testDir, "*", SearchOption.TopDirectoryOnly))
|
||||||
|
{
|
||||||
|
Console.WriteLine(" " + f + " attrs=" + File.GetAttributes(f));
|
||||||
|
}
|
||||||
|
Console.WriteLine(" dossier attrs=" + new DirectoryInfo(testDir).Attributes);
|
||||||
|
Console.WriteLine(" HasCustomColor=" + FolderColorizer.HasCustomColor(testDir));
|
||||||
|
|
||||||
|
string iniPath = Path.Combine(testDir, "desktop.ini");
|
||||||
|
Console.WriteLine("--- desktop.ini ---");
|
||||||
|
Console.WriteLine(File.ReadAllText(iniPath));
|
||||||
|
|
||||||
|
string icoPath = Path.Combine(testDir, ".colorpicker_folder.ico");
|
||||||
|
var icoBytes = File.ReadAllBytes(icoPath);
|
||||||
|
Console.WriteLine("Taille .ico: " + icoBytes.Length + " octets, count entries=" + BitConverter.ToUInt16(icoBytes, 4));
|
||||||
|
|
||||||
|
FolderColorizer.RestoreDefault(testDir);
|
||||||
|
Console.WriteLine("Apres RestoreDefault:");
|
||||||
|
foreach (var f in Directory.GetFiles(testDir, "*", SearchOption.TopDirectoryOnly))
|
||||||
|
{
|
||||||
|
Console.WriteLine(" " + f);
|
||||||
|
}
|
||||||
|
Console.WriteLine(" dossier attrs=" + new DirectoryInfo(testDir).Attributes);
|
||||||
|
Console.WriteLine(" HasCustomColor=" + FolderColorizer.HasCustomColor(testDir));
|
||||||
|
Console.WriteLine("Fichiers restants: " + Directory.GetFiles(testDir).Length);
|
||||||
|
|
||||||
|
Directory.Delete(testDir, true);
|
||||||
|
Console.WriteLine("OK - test termine sans exception.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user