Initial : marketplace + 2 plugins (syncfusion-ribbon-accent, offscreen-winforms-render)
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"$schema": "https://code.claude.com/docs/plugins/marketplace-schema.json",
|
||||
"name": "ara-claude-plugins",
|
||||
"description": "Plugins Claude Code pour le développement WinForms / Syncfusion (ARA Informatique).",
|
||||
"owner": {
|
||||
"name": "Julien Cluzel"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "syncfusion-ribbon-accent",
|
||||
"source": "./plugins/syncfusion-ribbon-accent",
|
||||
"description": "Couleur d'accent personnalisée (live) sur un ruban Syncfusion WinForms Office2016 : ruban, backstage (dont le SURVOL des items), onglets de contenu, grilles SfDataGrid. Le bon levier par élément + les pièges.",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"keywords": ["syncfusion", "winforms", "ribbon", "office2016", "theme", "accent", "backstage", "sfdatagrid"],
|
||||
"category": "dev"
|
||||
},
|
||||
{
|
||||
"name": "offscreen-winforms-render",
|
||||
"source": "./plugins/offscreen-winforms-render",
|
||||
"description": "Vérifier/déboguer l'aspect d'une IHM WinForms sans bureau interactif (agent/CI/headless) : rendu hors écran via PrintWindow → PNG relisible et échantillonnable au pixel.",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"keywords": ["winforms", "render", "offscreen", "printwindow", "headless", "screenshot", "testing"],
|
||||
"category": "dev"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
bin/
|
||||
*.log
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Julien Cluzel
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,43 @@
|
||||
# ara-claude-plugins
|
||||
|
||||
Marketplace de **plugins Claude Code** pour le développement **WinForms / Syncfusion**.
|
||||
Chaque plugin apporte un *skill* réutilisable, issu d'un projet réel (migration WinDev → .NET + Syncfusion).
|
||||
|
||||
## Plugins
|
||||
|
||||
| Plugin | Skill | Pour quoi |
|
||||
|---|---|---|
|
||||
| **syncfusion-ribbon-accent** | `/syncfusion-ribbon-accent:syncfusion-ribbon-accent` | Appliquer une **couleur d'accent personnalisée** (live) à un ruban Syncfusion WinForms Office2016 : ruban, backstage (dont le **survol** des items), onglets de contenu, grilles `SfDataGrid`. Le bon levier par élément + les pièges. |
|
||||
| **offscreen-winforms-render** | `/offscreen-winforms-render:offscreen-winforms-render` | **Vérifier/déboguer une IHM WinForms sans bureau interactif** (agent, CI, headless) : rendu hors écran via `PrintWindow` → PNG relisible et échantillonnable au pixel. |
|
||||
|
||||
Réf. testée : Syncfusion Essential Studio **WinForms 33.2.x**, .NET, C#.
|
||||
|
||||
## Installation
|
||||
|
||||
```text
|
||||
/plugin marketplace add https://repos.ara-it.info/ARA-IT/ara-claude-plugins.git
|
||||
/plugin install syncfusion-ribbon-accent@ara-claude-plugins
|
||||
/plugin install offscreen-winforms-render@ara-claude-plugins
|
||||
```
|
||||
|
||||
Puis `/reload-plugins` si installé en cours de session. Les skills s'invoquent ensuite via
|
||||
`/<plugin>:<skill>` (ou se déclenchent automatiquement selon le contexte).
|
||||
|
||||
Mettre à jour : `/plugin marketplace update ara-claude-plugins`.
|
||||
|
||||
## Structure du repo
|
||||
|
||||
```
|
||||
.claude-plugin/marketplace.json # catalogue (liste les 2 plugins)
|
||||
plugins/
|
||||
├── syncfusion-ribbon-accent/
|
||||
│ ├── .claude-plugin/plugin.json
|
||||
│ └── skills/syncfusion-ribbon-accent/SKILL.md
|
||||
└── offscreen-winforms-render/
|
||||
├── .claude-plugin/plugin.json
|
||||
└── skills/offscreen-winforms-render/SKILL.md
|
||||
```
|
||||
|
||||
## Licence
|
||||
|
||||
MIT — voir [LICENSE](LICENSE).
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"$schema": "https://code.claude.com/docs/plugins/plugin-schema.json",
|
||||
"name": "offscreen-winforms-render",
|
||||
"description": "Vérifier ou déboguer l'aspect visuel d'une IHM WinForms (.NET, y compris Syncfusion) sans bureau interactif (agent, CI, headless) — rendu hors écran via PrintWindow + thread STA → PNG relisible ET échantillonnable au pixel. Inclut : forcer un état de survol, ouvrir une backstage, injecter une couleur de test.",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "Julien Cluzel"
|
||||
},
|
||||
"license": "MIT",
|
||||
"repository": "https://repos.ara-it.info/ARA-IT/ara-claude-plugins"
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
---
|
||||
name: offscreen-winforms-render
|
||||
description: À utiliser pour VÉRIFIER ou DÉBOGUER l'aspect visuel d'une IHM WinForms (.NET, y compris Syncfusion) quand il n'y a PAS de bureau interactif (agent, CI, headless) — où CopyFromScreen échoue. Rend la fenêtre HORS ÉCRAN dans un PNG (PrintWindow + thread STA) que l'on peut relire ET échantillonner au pixel (preuve empirique des couleurs/du layout). Inclut : forcer un état de survol, ouvrir une backstage, injecter une couleur de test.
|
||||
---
|
||||
|
||||
# Rendu d'artefact offscreen (vérifier une IHM WinForms sans la lancer)
|
||||
|
||||
**But** : produire un **PNG** du rendu réel d'une fenêtre WinForms sans bureau interactif, pour le **relire**
|
||||
et l'**échantillonner pixel par pixel** (preuve chiffrée). Portable : tout projet .NET WinForms (Syncfusion ou non).
|
||||
|
||||
## Pourquoi
|
||||
|
||||
- En agent/CI, pas de bureau interactif : `Graphics.CopyFromScreen` échoue (« Descripteur non valide »).
|
||||
- Sans retour visuel, on tourne en rond sur les bugs d'IHM (couleur, layout).
|
||||
- Parade : **dessiner la fenêtre hors écran dans un bitmap** via `PrintWindow`, sauver un PNG, puis (1) le relire,
|
||||
(2) l'échantillonner (`bmp.GetPixel(x,y)`) pour comparer des valeurs RGB attendues.
|
||||
|
||||
## Prérequis
|
||||
|
||||
- Console jetable `net10.0-windows` (`OutputType=WinExe`, `UseWindowsForms=true`). Dossier préfixé `_` (gitignoré).
|
||||
- Si l'IHM a une **licence** (Syncfusion…) : l'enregistrer, sinon un dialogue modal **gèle** le rendu.
|
||||
- Si l'IHM a un **thème** chargé au démarrage : le charger pareil que l'app.
|
||||
- Pour rendre la VRAIE fenêtre : référencer le projet applicatif (`ProjectReference`).
|
||||
|
||||
## Gabarit
|
||||
|
||||
```csharp
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
|
||||
var th = new Thread(Run); // 1) thread STA obligatoire
|
||||
th.SetApartmentState(ApartmentState.STA);
|
||||
th.Start(); th.Join();
|
||||
|
||||
[DllImport("user32.dll")] static extern bool PrintWindow(IntPtr h, IntPtr hdc, uint flags);
|
||||
|
||||
void Run()
|
||||
{
|
||||
// 2) Licence éventuelle (sinon dialogue d'essai modal => blocage)
|
||||
// Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("...");
|
||||
// 3) Thème éventuel, chargé comme dans l'app réelle
|
||||
// SfSkinManager.LoadAssembly(typeof(Office2016Theme).Assembly);
|
||||
|
||||
var f = new MyForm { StartPosition = FormStartPosition.Manual, Location = new Point(-3000, 0) }; // HORS écran
|
||||
f.Show();
|
||||
for (int i = 0; i < 10; i++) { Application.DoEvents(); Thread.Sleep(80); } // 4) laisser peindre (PAS Application.Run)
|
||||
|
||||
using var bmp = new Bitmap(f.Width, f.Height);
|
||||
using (var g = Graphics.FromImage(bmp))
|
||||
{
|
||||
var hdc = g.GetHdc();
|
||||
PrintWindow(f.Handle, hdc, 2); // 5) flag 2 = PW_RENDERFULLCONTENT (obligatoire)
|
||||
g.ReleaseHdc(hdc);
|
||||
}
|
||||
bmp.Save(@"C:\chemin\rendu.png");
|
||||
var c = bmp.GetPixel(450, 12); // 6) preuve empirique chiffrée
|
||||
Console.WriteLine($"pixel = {c.R},{c.G},{c.B}");
|
||||
f.Close();
|
||||
}
|
||||
```
|
||||
|
||||
## Recettes utiles
|
||||
|
||||
- **Plusieurs variantes en une exécution** : une fonction `Capture(name, build)` par variante, échantillonner le pixel décisif → comparer les RGB. Injecter une **couleur de test distinctive** (rouge/orange/violet), pas la couleur par défaut, pour distinguer « appliqué » de « inchangé ».
|
||||
- **Rendre le VRAI form** (un mock minimal ne reproduit pas certains bugs de thème/skin) : référencer le projet, instancier la fenêtre. Accéder aux champs privés par réflexion si besoin :
|
||||
```csharp
|
||||
var fld = typeof(MyForm).GetField("backStageView", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
```
|
||||
- **Ouvrir une backstage Syncfusion** : `backStageView.ShowBackStage();`
|
||||
- **Forcer un état de survol** (capturer un hover sans souris) : `button.State = ButtonAdvState.MouseOver;` puis `Invalidate()`. (⚠️ un `State` forcé n'est pas toujours fidèle à 100 % au survol réel selon le contrôle — recouper avec la valeur de propriété et/ou un test live.)
|
||||
|
||||
## Pièges (vérifiés)
|
||||
|
||||
- **Thread STA obligatoire** (`SetApartmentState(STA)`), sinon plantage à l'instanciation.
|
||||
- **Licence avant tout** : sans enregistrement, le dialogue d'essai modal gèle le rendu.
|
||||
- **Thème chargé** comme dans l'app, sinon rendu non représentatif.
|
||||
- **`PrintWindow` flag = 2** (`PW_RENDERFULLCONTENT`) : `0`/`1` ratent les contrôles peints en différé (noir/partiel).
|
||||
- **Fenêtre hors écran** (`Location` négatif + `StartPosition=Manual`).
|
||||
- **Laisser peindre** : `Show()` + boucle `Application.DoEvents()`/`Sleep` (PAS `Application.Run`).
|
||||
- **Coordonnées d'échantillonnage** : repérer les bons `(x,y)` en regardant d'abord le PNG (un contrôle peut être repositionné au runtime ≠ ses `Bounds` de design).
|
||||
- **Pas de `CopyFromScreen`** en headless (échoue) — c'est ce que `PrintWindow` contourne.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Créer `_render/` (gitignoré).
|
||||
2. Composer un contrôle minimal OU instancier la vraie fenêtre ; faire plusieurs variantes ; échantillonner.
|
||||
3. **Relire** le PNG (juger l'aspect) **et** lire la sortie console (preuve chiffrée).
|
||||
4. Itérer, puis **supprimer** le dossier jetable.
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"$schema": "https://code.claude.com/docs/plugins/plugin-schema.json",
|
||||
"name": "syncfusion-ribbon-accent",
|
||||
"description": "Couleur d'accent personnalisée (live) sur un ruban Syncfusion WinForms Office2016 — ruban, backstage (dont le survol des items), onglets de contenu (TabControlAdv), grilles SfDataGrid. Donne le bon levier par élément et les pièges (ThemeStyle ignoré, ThemeName à conserver, BackStageItemHoverColor, FlattenHierarchy…). Réf. testée : Syncfusion WinForms 33.2.x.",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "Julien Cluzel"
|
||||
},
|
||||
"license": "MIT",
|
||||
"repository": "https://repos.ara-it.info/ARA-IT/ara-claude-plugins"
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
---
|
||||
name: syncfusion-ribbon-accent
|
||||
description: À utiliser pour IMPLÉMENTER ou DÉBOGUER une couleur d'accent personnalisée (live, choisie par l'utilisateur) sur une IHM Syncfusion WinForms Office2016 — ruban (RibbonControlAdv), backstage (BackStage/menu Fichier, y compris le SURVOL des items), onglets de contenu (TabControlAdv) et grilles (SfDataGrid). Donne le bon levier par élément et les pièges (ThemeStyle ignoré, ThemeName à ne pas vider, BackStageItemHoverColor, FlattenHierarchy…). Réf. testée : Syncfusion WinForms 33.2.x.
|
||||
---
|
||||
|
||||
# Couleur d'accent sur un ruban Syncfusion WinForms (Office2016)
|
||||
|
||||
**But** : faire suivre une **couleur d'accent libre** à TOUTE l'IHM (ruban, backstage, onglets, grilles), en live.
|
||||
**Testé** : Syncfusion Essential Studio **WinForms 33.2.10**, .NET 10, C#.
|
||||
**Prérequis** : `SfSkinManager.LoadAssembly(typeof(Office2016Theme).Assembly);` au démarrage.
|
||||
|
||||
## Règle d'or — chaque zone a SON mécanisme (ne pas les confondre)
|
||||
|
||||
| Élément | Bon levier (33.2.x) | À NE PAS faire |
|
||||
|---|---|---|
|
||||
| **Ruban** (bandeau, onglets, Fichier, boutons système) | `ribbon.Office2016ColorTable` (**Clear + Add d'UNE table**), en **gardant** `ThemeName="Office2016"` | `ribbon.ThemeStyle` (ignoré en live) ; vider `ThemeName` (ruban plat « touch ») |
|
||||
| **Backstage — titre + bouton retour ←** | `ribbon.ThemeStyle.BackStageStyle` (`TitleBarBackColor`, `ControlBoxBackColor`…), **ré-assigner** `ribbon.ThemeStyle` | — |
|
||||
| **Backstage — items (onglets+boutons) repos/SURVOL/sélection** | `ribbon.Office2016ColorTable.BackStageItem*` (le renderer `BackStage2016` lit cette table) | `BackStageButton.BackColor`/`MetroColor`/`OverrideFormManagedColor`/`ThemeStyle` (écrasés par le renderer) |
|
||||
| **Backstage — onglet actif** | `backStage.ActiveTabColor` / `ActiveTabForeColor` | — |
|
||||
| **Onglets de contenu** (`TabControlAdv`) | `content.ActiveTabColor` / `ActiveTabForeColor` | — |
|
||||
| **Grilles** (`SfDataGrid`) | surcharge directe de `grid.Style` | chercher un `ThemeSettings` (inexistant en 33.2.10) |
|
||||
| **QuickAccess Toolbar** (retrait) | `ribbon.QuickPanelVisible=false` + `ribbon.ShowQuickItemsDropDownButton=false` | — |
|
||||
|
||||
**3 principes** : (1) **garder** `ribbon.ThemeName="Office2016"` (le vider casse le rendu) ; (2) `Office2016ColorTable` est une `BindingList` **sans clé** → **une seule table** (`Clear()`+`Add()`) ; (3) le renderer Office2016 lit cette table pour le ruban **ET** la backstage.
|
||||
|
||||
## Pièges (à ne pas redécouvrir)
|
||||
|
||||
1. `ribbon.ThemeStyle` n'a **aucun effet live** sur le bandeau du ruban (le skin repeint par-dessus) → `Office2016ColorTable`.
|
||||
2. Vider `ribbon.ThemeName` colore le bandeau MAIS retire le skin → rendu plat « touch », laid. **Garder `"Office2016"`.**
|
||||
3. `Office2016ColorTable` = `BindingList` sans clé/scheme → **une seule entrée** suffit.
|
||||
4. **Survol des items backstage** : ni `BackStageButton.BackColor`/`MetroColor`/`OverrideFormManagedColor`+`CustomManagedColor`/`Appearance=Metro`/`ButtonAdvVisualStyle.HoverBackColor` — le renderer peint et lit la **color table** → **`BackStageItemHoverColor`**.
|
||||
5. `backStage.ThemeName` se fait **réécraser** par SfSkinManager (`BackStage2016Renderer`) ; le vider est inopérant.
|
||||
6. **Noms `[Obsolete]`** : `BackStage*Tab*Color`/`BackStage*Button*Color` → unifiés en **`BackStageItem*`**.
|
||||
7. `SfSkinManager` 33.2.10 = `LoadAssembly` + `SetTheme` seulement (pas de `ThemeSettings`/`RegisterThemeSettings`).
|
||||
8. `Office2016ColorTable` ne s'applique que sous `Office2016ColorScheme.Colorful`.
|
||||
9. **Réflexion incomplète = fausse conclusion** : lister les propriétés d'un type Syncfusion SANS `BindingFlags.FlattenHierarchy` rate les **membres hérités** (piège qui avait fait conclure à tort que `BackStageItemHoverColor` n'existait pas). **Toujours `Public|Instance|FlattenHierarchy`** + signaler les `[Obsolete]`.
|
||||
|
||||
## Vérification (environnement sans bureau / agent)
|
||||
|
||||
- **Rendre le VRAI form** offscreen (un mock minimal ne reproduit PAS le bleu backstage). `PrintWindow` (flag 2) + thread STA → PNG relisible + `bmp.GetPixel`. Cf. méthode de rendu offscreen.
|
||||
- Ouvrir la backstage par réflexion : `backStageView.ShowBackStage()` (champ privé).
|
||||
- **Forcer un survol** pour le capturer sans souris : `btnX.State = ButtonAdvState.MouseOver;` puis `Invalidate()`.
|
||||
- Injecter une **couleur de test distinctive** (orange/rouge/violet), pas l'accent par défaut, pour distinguer « appliqué » de « inchangé ».
|
||||
- **Vérifier l'API par réflexion AVANT de coder** (`MetadataLoadContext`, `FlattenHierarchy`).
|
||||
|
||||
## Checklist d'intégration
|
||||
|
||||
1. `SfSkinManager.LoadAssembly(typeof(Office2016Theme).Assembly)`.
|
||||
2. Ruban : `RibbonStyle.Office2016` + `Office2016ColorScheme.Colorful` + `ThemeName="Office2016"` + `CanOverrideStyle=true` + `MenuColor=accent`.
|
||||
3. **Une** `Office2016ColorTable` (chrome=accent, corps clair, `BackStageItem*`=accent) → `Clear()`+`Add()`.
|
||||
4. `ThemeStyle.BackStageStyle` : `TitleBarBackColor`/`ControlBoxBackColor` (+hover/pressed) → ré-assigner `ThemeStyle`.
|
||||
5. `backStage.ActiveTabColor` + `content.ActiveTabColor`.
|
||||
6. Grilles : `grid.Style.*` (sélection/en-tête/bordure/ascenseurs) + ré-application live.
|
||||
7. QAT retirée si inutile.
|
||||
8. Helpers `ForeColorFor` / `Shade` / `Tint`.
|
||||
9. **Vérifier au rendu offscreen** (vrai form + survol forcé) avant de conclure.
|
||||
|
||||
## Implémentation de référence (copiable)
|
||||
|
||||
```csharp
|
||||
using Syncfusion.Windows.Forms; // BackStage, BackStageButton
|
||||
using Syncfusion.Windows.Forms.Tools; // RibbonForm, RibbonControlAdv, Office2016ColorTable, TabControlAdv
|
||||
using Syncfusion.WinForms.Controls; // SfSkinManager
|
||||
using Syncfusion.WinForms.DataGrid; // SfDataGrid
|
||||
|
||||
internal static class AppTheme
|
||||
{
|
||||
public static Color AccentColor { get; set; } = ColorTranslator.FromHtml("#0099CC");
|
||||
public const string SfThemeName = "Office2016Colorful";
|
||||
|
||||
// === RUBAN + BACKSTAGE (titre/bouton retour) ===
|
||||
public static void ApplyOffice2016(RibbonForm form, RibbonControlAdv ribbon, Color accent)
|
||||
{
|
||||
ribbon.RibbonStyle = RibbonStyle.Office2016;
|
||||
ribbon.Office2016ColorScheme = Office2016ColorScheme.Colorful;
|
||||
ribbon.ThemeName = "Office2016";
|
||||
ribbon.CanOverrideStyle = true;
|
||||
ribbon.MenuColor = accent;
|
||||
|
||||
ribbon.Office2016ColorTable.Clear();
|
||||
ribbon.Office2016ColorTable.Add(BuildOffice2016ColorTable(accent));
|
||||
|
||||
Color fore = ForeColorFor(accent);
|
||||
var themeStyle = ribbon.ThemeStyle;
|
||||
var bs = themeStyle.BackStageStyle;
|
||||
bs.TitleBarBackColor = accent; bs.TitleBarForeColor = fore;
|
||||
bs.ControlBoxBackColor = accent; // bouton retour ←
|
||||
bs.HoverControlBoxBackColor = Shade(accent, 0.12);
|
||||
bs.PressedControlBoxBackColor = Shade(accent, 0.20);
|
||||
bs.ItemBackColor = accent; bs.ItemForeColor = fore;
|
||||
bs.SelectedItemBackColor = Shade(accent, 0.20); bs.SelectedItemForeColor = fore;
|
||||
bs.HoverItemBackColor = Shade(accent, 0.12); bs.HoverItemForeColor = fore;
|
||||
ribbon.ThemeStyle = themeStyle;
|
||||
|
||||
ribbon.Refresh();
|
||||
ribbon.Invalidate(true);
|
||||
}
|
||||
|
||||
private static Office2016ColorTable BuildOffice2016ColorTable(Color accent)
|
||||
{
|
||||
Color fore = ForeColorFor(accent);
|
||||
Color body = ColorTranslator.FromHtml("#F1F1F1");
|
||||
Color bodyText = ColorTranslator.FromHtml("#575757");
|
||||
Color border = ColorTranslator.FromHtml("#D2D2D2");
|
||||
Color hover = ColorTranslator.FromHtml("#C5C5C5");
|
||||
return new Office2016ColorTable
|
||||
{
|
||||
// Chrome à l'accent
|
||||
HeaderColor = accent, TabBackColor = accent, TitleColor = fore,
|
||||
TabForeColor = fore, HoverTabForeColor = fore, SelectedTabColor = accent,
|
||||
CheckedTabColor = body, CheckedTabForeColor = accent,
|
||||
FileMenuForeColor = fore, FileMenuHoverForeColor = fore,
|
||||
SystemButtonBackground = accent, ControlBoxForeColor = fore,
|
||||
CloseButtonBackground = ColorTranslator.FromHtml("#E81123"),
|
||||
// Items backstage (le renderer lit cette table) — SURVOL = BackStageItemHoverColor
|
||||
BackStageItemForeColor = fore,
|
||||
BackStageItemHoverColor = Shade(accent, 0.16),
|
||||
BackStageItemHoverForeColor = fore,
|
||||
BackStageItemSelectionColor = Shade(accent, 0.26),
|
||||
BackStageItemSelectionForeColor = fore,
|
||||
BackStageTitleColor = ColorTranslator.FromHtml("#3A3A3A"),
|
||||
// Corps clair, lisible
|
||||
CaptionBackColor = body, CaptionForeColor = bodyText,
|
||||
ToolStripBackColor = body, PanelBackColor = body, RibbonPanelBorderColor = border,
|
||||
ToolStripItemForeColor = bodyText, ToolStripSpliterColor = border,
|
||||
ButtonBackgroundHovered = hover, ButtonBackgroundSelected = hover,
|
||||
ButtonBackgroundPressed = ColorTranslator.FromHtml("#969696"),
|
||||
};
|
||||
}
|
||||
|
||||
// === ONGLETS DE CONTENU ===
|
||||
public static void ApplyContentTabs(TabControlAdv content, Color accent)
|
||||
{
|
||||
content.ActiveTabColor = accent;
|
||||
content.ActiveTabForeColor = ForeColorFor(accent);
|
||||
content.Refresh(); content.Invalidate(true);
|
||||
}
|
||||
|
||||
// === BACKSTAGE : onglet actif (le reste via la color table) ===
|
||||
public static void ApplyBackStageItems(BackStage backStage, Color accent)
|
||||
{
|
||||
backStage.ActiveTabColor = accent;
|
||||
backStage.ActiveTabForeColor = ForeColorFor(accent);
|
||||
backStage.Invalidate(true);
|
||||
}
|
||||
|
||||
// === GRILLES ===
|
||||
public static void ApplySfControlTheme(Control control) => SfSkinManager.SetTheme(control, SfThemeName);
|
||||
|
||||
public static void ApplyGridAccent(SfDataGrid grid, Color accent)
|
||||
{
|
||||
grid.Style.SelectionStyle.BackColor = Tint(accent, 0.55);
|
||||
grid.Style.SelectionStyle.TextColor = Color.Black;
|
||||
grid.Style.HeaderStyle.SortIconColor = accent;
|
||||
grid.Style.HeaderStyle.FilterIconColor = accent;
|
||||
grid.Style.BorderColor = accent;
|
||||
grid.Style.VerticalScrollBar.ThumbColor = Tint(accent, 0.45);
|
||||
grid.Style.VerticalScrollBar.ThumbHoverColor = accent;
|
||||
grid.Style.HorizontalScrollBar.ThumbColor = Tint(accent, 0.45);
|
||||
grid.Style.HorizontalScrollBar.ThumbHoverColor = accent;
|
||||
grid.Invalidate();
|
||||
}
|
||||
|
||||
public static void RefreshGridAccents(Control root, Color accent)
|
||||
{
|
||||
foreach (Control c in root.Controls)
|
||||
{
|
||||
if (c is SfDataGrid g) ApplyGridAccent(g, accent);
|
||||
if (c.HasChildren) RefreshGridAccents(c, accent);
|
||||
}
|
||||
}
|
||||
|
||||
// === HELPERS ===
|
||||
private static Color ForeColorFor(Color c)
|
||||
=> (0.299 * c.R + 0.587 * c.G + 0.114 * c.B) / 255.0 > 0.55 ? Color.Black : Color.White;
|
||||
public static Color Tint(Color c, double t) => Color.FromArgb(c.A,
|
||||
(int)(c.R + (255 - c.R) * t), (int)(c.G + (255 - c.G) * t), (int)(c.B + (255 - c.B) * t));
|
||||
private static Color Shade(Color c, double f) => Color.FromArgb(c.A,
|
||||
(int)(c.R * (1 - f)), (int)(c.G * (1 - f)), (int)(c.B * (1 - f)));
|
||||
}
|
||||
```
|
||||
|
||||
### Câblage (au démarrage ET dans le picker de couleur)
|
||||
|
||||
```csharp
|
||||
AppTheme.ApplyOffice2016(this, ribbon, accent);
|
||||
AppTheme.ApplyContentTabs(content, accent);
|
||||
AppTheme.ApplyBackStageItems(backStage, accent);
|
||||
AppTheme.RefreshGridAccents(content, accent); // grilles déjà ouvertes
|
||||
// QAT : ribbon.QuickPanelVisible = false; ribbon.ShowQuickItemsDropDownButton = false;
|
||||
// + persister la couleur et la relire au démarrage
|
||||
```
|
||||
|
||||
> Guide long + récit complet : `docs/syncfusion-ribbon-couleur-accent.md` (dans le repo d'origine CapToilettage).
|
||||
> Technique de vérification : `docs/methode-rendu-offscreen.md`.
|
||||
Reference in New Issue
Block a user