System Architecture

Three independent layers cooperate to paint everything on screen:

LayerClass / NamespaceResponsibility
1 — Theme Layer BeepThemesManager
ThemeManagement/
Holds the active IBeepTheme (color palette, typography, spacing tokens). Fires ThemeChanged / DpiChanged events. All controls subscribe and call ApplyTheme() in response.
2 — Style Coordinator BeepStyling
Styling/BeepStyling.cs
Central static class. Maps FormStyle ↔ BeepControlStyle, routes every paint call to the correct specialist painter, and exposes helper shortcuts (GetRadius, GetBorderColor, …). Does not draw anything itself.
3 — Painter Subsystems 7 painter folders
170+ classes
Each painter class owns one operation (background, border, text, shadow, …) for one design system. Painters call the 5 helper systems for style-specific values (colors, spacing, borders, shadows, typography).

How BaseControl fits in

BaseControl is the root for every Beep UI control. Its painting pipeline:

  1. OnPaint → DrawContent(g)
  2. EnsurePainter() — selects an IBaseControlPainter based on PainterKind
  3. Painter calls BeepStyling.PaintStyleBackground / PaintStyleBorder / PaintStyleText using the control's current BeepControlStyle
  4. Derived control overrides DrawContent to add specific content inside DrawingRect

How BeepiFormPro fits in

BeepiFormPro is the themed borderless form host. Its pipeline is parallel but separate from the control pipeline:

  1. FormStyle property changes → ApplyFormStyle()
  2. BeepStyling.GetControlStyle(FormStyle) → syncs BeepStyling.CurrentControlStyle so controls inside the form automatically pick up the same style
  3. PaintersFactory.GetPainter(FormStyle) → returns a cached IFormPainter
  4. IFormPainter.CalculateLayoutAndHitAreas() positions caption bar, buttons, title; IFormPainter.PaintBackground / PaintCaptionBar / PaintBorder render each layer
Key relationship: Setting BeepiFormPro.FormStyle calls BeepStyling.ApplyFormStyle() which sets BeepStyling.CurrentControlStyle. Every control inside that form reads BeepStyling.CurrentControlStyle during paint, so the form chrome and all controls always share the same design system.

BeepStyling — The Coordinator

Static class in TheTechIdea.Beep.Winform.Controls.Styling. Single source of truth for which design system is currently active.

Global State

MemberTypeDescription
CurrentControlStyleBeepControlStyleThe active design system for all controls. Default: Minimal.
CurrentThemeIBeepThemeThe active theme object (colors, typography). Set from BeepThemesManager.CurrentTheme.
UseThemeColorsboolWhen true (default), color methods prefer theme colors over hard-coded style defaults.
ImageCachedPaintersDictionary<string, ImagePainter>Image painter cache. Shared across all controls.

Style Management Methods

MethodDescription
SetControlStyle(BeepControlStyle)Change the global style and fire ControlStyleChanged event.
GetControlStyle()Return CurrentControlStyle.
ApplyFormStyle(FormStyle)Map a FormStyle to the corresponding BeepControlStyle and set it.
GetControlStyle(FormStyle)Return the BeepControlStyle for a given FormStyle (pure lookup, no side effects).
GetFormStyle(BeepControlStyle)Reverse lookup: BeepControlStyle → FormStyle.
GetThemeStyle(BeepControlStyle)Return the theme name associated with a control style.

Paint Entry Points

MethodDescription
PaintStyleBackground(g, path)Paint background using CurrentControlStyle.
PaintStyleBackground(g, path, BeepControlStyle)Paint background for a specific style.
PaintStyleBorder(g, path, isFocused)Paint border using CurrentControlStyle and focus state.
PaintStyleBorder(g, path, isFocused, BeepControlStyle)Paint border for a specific style.
PaintStyleText(g, path, text, isFocused)Paint text using CurrentControlStyle.
PaintStyleText(g, path, text, isFocused, BeepControlStyle)Paint text for a specific style.
PaintStyleSpinnerButtons(g, upPath, downPath, isFocused, style)Paint numeric up/down buttons for a specific style.

Style Value Shortcuts

MethodReturnsDescription
GetRadius(BeepControlStyle)intCorner radius in pixels for the style.
GetBorderThickness(BeepControlStyle)floatBorder stroke width.
GetPadding(BeepControlStyle)intInternal padding.
GetBackgroundColor(BeepControlStyle)ColorBackground color (theme-aware).
GetForegroundColor(BeepControlStyle)ColorForeground/text color (theme-aware).
GetBorderColor(BeepControlStyle)ColorBorder color (theme-aware).
GetThemeColor(themeColorKey)ColorRead a named color from the current theme (e.g., "Primary", "Accent").
CreateControlPath(bounds, FormStyle)GraphicsPathCreate the clipping/rendering path for a control using a form style.
CreateControlStylePath(bounds, BeepControlStyle)GraphicsPathCreate the path using a direct control style.

Painter Subsystems (7 Folders)

Each folder contains style-specific painter classes. All painters are static and stateless; they receive all context via parameters.

FolderClassesSignature PatternResponsibility
BackgroundPainters/ 36+ Paint(Graphics, GraphicsPath, BeepControlStyle, IBeepTheme, bool) Fill the control background. Effects include: flat fill, gradient, glass/acrylic, neon glow, neumorphism, mica, frosted glass, dark glow, gradient burst, and more.
BorderPainters/ 27 Paint(Graphics, GraphicsPath, bool, BeepControlStyle, IBeepTheme, bool, ControlState) Draw border strokes. Variations: solid, double, dashed, glowing, focus-ring, accent-side, thick/thin.
TextPainters/ 5 Paint(Graphics, Rectangle, string, bool, BeepControlStyle, IBeepTheme, bool) Render text with the correct font, color, weight, and spacing for each design system family.
SpinnerButtonPainters/ 26 PaintButtons(Graphics, Rectangle, Rectangle, bool, BeepControlStyle, IBeepTheme, bool) Render up/down arrow buttons for numeric controls with style-appropriate visuals.
ShadowPainters/ 27 Paint(Graphics, GraphicsPath, int, IBeepTheme) Render drop shadows and elevation effects below controls. Includes dual shadows for neumorphism.
PathPainters/ 23 Fill(Graphics, GraphicsPath, BeepControlStyle, IBeepTheme) Fill arbitrary GraphicsPath shapes (shapes, overlays, decorations) with style-appropriate brushes.
ImagePainters/ 1 (static) See StyledImagePainter Cached image rendering with rounded corners, shape clipping, tint, and opacity. Supports 10+ geometric clip shapes.

Factory Classes

Each painter folder has a companion factory for lookup and caching:

FactoryLocationMethod
BackgroundPainterFactoryBackgroundPainters/CreatePainter(BeepControlStyle) → IBackgroundPainter
BorderPainterFactoryBorderPainters/CreatePainter(BeepControlStyle) → IBorderPainter
ShadowPainterFactoryShadows/CreatePainter(BeepControlStyle) → IShadowPainter
PaintersFactory (Forms)Forms/ModernForm/GetPainter(FormStyle) → IFormPainter (cached)

Style Helper Systems (5 Systems)

All helpers are static classes that accept BeepControlStyle and return design-system-specific values via switch expressions. No base classes — every value is explicit.

ClassLocationKey Methods
StyleColors Colors/ GetBackground(style), GetForeground(style), GetBorder(style), GetAccent(style), GetPrimary(style)
StyleSpacing Spacing/ GetPadding(style), GetMargin(style), GetItemHeight(style)
StyleBorders Borders/ GetRadius(style), GetBorderWidth(style), HasBorder(style)
StyleShadows Shadows/ HasShadow(style), GetShadowOpacity(style), GetShadowBlur(style), UsesDualShadows(style)
StyleTypography Typography/ GetFontFamily(style), GetFontSize(style), GetFontWeight(style), GetLetterSpacing(style)

BaseControl Painting Pipeline

Every Beep control inherits from BaseControl (ContainerControl). Understanding this pipeline is essential for creating custom controls.

File Structure

FileResponsibility
BaseControl.csCore class declaration, private fields, IsReadyForDrawing guard, state flags (IsHovered, IsPressed, IsFocused)
BaseControl.Methods.csEnsurePainter(), InvokeBorderPainter(), ApplyTheme(), UpdateBorderPainter()
BaseControl.Properties.csAll public properties: PainterKind, BorderPainterStyle, Theme, IsChild, layout properties
BaseControl.LayoutManagement.csDrawingRect calculation, label/icon/error layout
BaseControl.Events.csMouse events, keyboard events, theme subscription/unsubscription
BaseControl.LabelandError.csLabel text, helper text, error message regions
BaseControl.Tooltip.csTooltip creation and theme theming
BaseControl.Win32.csWM_NCHITTEST overrides, flicker reduction
Helpers/Painters/IBaseControlPainter.csPainter interface: UpdateLayout(), Paint(), UpdateHitAreas()
Helpers/Painters/ClassicBaseControlPainter.csDefault painter: shadow → fill → border → gradient → image → text

Render Sequence

protected override void OnPaint(PaintEventArgs e)
{
    if (!IsReadyForDrawing) return;        // 1. Guard
    if (AllowBaseControlClear) e.Graphics.Clear(BackColor);

    DrawContent(e.Graphics);              // 2. Entry
}

protected virtual void DrawContent(Graphics g)
{
    EnsurePainter();                      // 3. Select painter
    _painter?.UpdateLayout(this);         // 4. Compute rects
    _painter?.Paint(g, this);             // 5. Render outer chrome
    _painter?.UpdateHitAreas(this);       // 6. Register hit zones
    // DrawingRect is now ready — derived control paints content here
}

Painter Kinds

PainterKindPainter ClassVisual Style
Classic (default)ClassicBaseControlPainterTraditional WinForms; configurable borders, shadows, gradients, state colors
None— (no painter)Control handles ALL rendering itself inside DrawContent
AutoClassicBaseControlPainterAlias for Classic

Border Painter Style (independent)

Separate from PainterKind. The BorderPainterStyle property selects a BeepControlStyle-specific border painter that is applied after the main painter renders the background:

// In a custom control constructor
PainterKind         = BaseControlPainterKind.Classic;   // outer chrome
BorderPainterStyle  = BeepControlStyle.Fluent2;          // border look

UpdateBorderPainter() calls BorderPainterFactory.CreatePainter(style) and also syncs BorderRadius, BorderThickness, and BorderColor from the style defaults.

Theme Subscription Pattern

// BaseControl automatically subscribes in its constructor:
BeepThemesManager.ThemeChanged += (s, e) => {
    _currentTheme = e.NewTheme;
    ApplyTheme();
    Invalidate();
};

// ApplyTheme() copies theme tokens to control properties:
public virtual void ApplyTheme()
{
    ForeColor    = _currentTheme.ForeColor;
    BorderColor  = _currentTheme.BorderColor;
    BackColor    = IsChild ? Parent.BackColor : _currentTheme.BackColor;
    _textFont    = BeepThemesManager.ToFont(_currentTheme.BodyMedium);
    // ...
}

Creating a Custom Control

public class MyBeepLabel : BaseControl
{
    public MyBeepLabel()
    {
        PainterKind        = BaseControlPainterKind.Classic;
        BorderPainterStyle = BeepControlStyle.Minimal;
        IsChild            = true;  // transparent background
    }

    protected override void DrawContent(Graphics g)
    {
        base.DrawContent(g);   // paints chrome into DrawingRect

        // DrawingRect is the inner content area after padding/border
        using var sf = new StringFormat { Alignment = StringAlignment.Center,
                                          LineAlignment = StringAlignment.Center };
        g.DrawString(Text, _textFont, new SolidBrush(ForeColor), DrawingRect, sf);
    }
}

BeepiFormPro Painting Pipeline

BeepiFormPro is a borderless Form subclass. Unlike controls, it has its own separate painter contract (IFormPainter) and factory.

File Structure

FileResponsibility
BeepiFormPro.csMain form class, FormStyle property, ApplyFormStyle()
BeepiFormPro.Core.csEnsureLayoutCalculated(), caching (_layoutDirty, _lastLayoutSize), InvalidateLayout()
BeepiFormPro.Drawing.csOnPaint → calls ActivePainter.PaintBackground / PaintCaptionBar / PaintBorder
BeepiFormPro.Theme.csApplyTheme(), BeepThemesManager.ThemeChanged subscription
BeepiFormPro.Events.csMouse events for caption drag, resize, button clicks
BeepiFormPro.Win32.csWM_NCHITTEST, borderless window hit testing
Managers/BeepiFormProHitAreaManager.csRegisters named hit zones (close, minimize, maximize, title, resize grips)
Managers/BeepiFormProInteractionManager.csTranslates mouse events to hit zone actions
PaintersFactory.csCaches one IFormPainter per FormStyle
Painters/IFormPainter.csContract: CalculateLayoutAndHitAreas, PaintBackground, PaintCaptionBar, PaintBorder

IFormPainter Contract

public interface IFormPainter
{
    void CalculateLayoutAndHitAreas(BeepiFormPro owner);
    void PaintBackground(Graphics g, BeepiFormPro owner);
    void PaintCaptionBar(Graphics g, BeepiFormPro owner);
    void PaintBorder(Graphics g, BeepiFormPro owner);
}

Each FormStyle has exactly one painter class (e.g., DraculaFormPainter, MacOSFormPainter). The painter owns everything: corner radius, caption height, window button positions, and visual effects for that style.

Layout Caching

To avoid recalculating hit areas on every paint, BeepiFormPro.Core.cs tracks a dirty flag. Layout only recalculates when:

  • Form size changes
  • FormStyle changes
  • Caption/button visibility changes
  • InvalidateLayout() is called explicitly

Available FormStyle Painters (40+)

  • ArcLinuxFormPainter
  • BrutalistFormPainter
  • CartoonFormPainter
  • ChatBubbleFormPainter
  • CyberpunkFormPainter
  • DraculaFormPainter
  • FluentFormPainter
  • GlassFormPainter
  • GlassmorphismFormPainter
  • GNOMEFormPainter
  • GruvBoxFormPainter
  • HolographicFormPainter
  • iOSFormPainter
  • KDEFormPainter
  • LinearFormPainter
  • MacOSFormPainter
  • MaterialFormPainter
  • MaterialYouFormPainter
  • Metro2FormPainter
  • MetroFormPainter
  • MinimalFormPainter
  • ModernFormPainter
  • NeoMorphismFormPainter
  • NeonFormPainter
  • NextJSFormPainter
  • NordFormPainter
  • NordicFormPainter
  • OneDarkFormPainter
  • PaperFormPainter
  • RadixUIFormPainter
  • RetroFormPainter
  • ShadcnFormPainter
  • SolarizedFormPainter
  • TerminalFormPainter
  • TokyoFormPainter
  • UbuntuFormPainter

StyledImagePainter

Static class in Styling/ImagePainters/. Handles all image rendering across the system with built-in caching, shape clipping, tinting, and opacity.

Caching

CacheKeyPurpose
_imageCacheimagePathDecoded Image objects from disk/resource
_painterCacheimagePathImagePainter objects for path-based drawing
_tintedCachepath+tint+opacityPre-rendered tinted bitmaps

All caches are ConcurrentDictionary — thread-safe for background pre-rendering.

Core Paint Methods

MethodDescription
Paint(g, GraphicsPath, imagePath, BeepControlStyle)Paint image clipped to a path with style-appropriate corner radius.
Paint(g, GraphicsPath, imagePath)Paint image clipped to a path with no radius (raw path clip).
PaintWithTint(g, path, imagePath, tint, opacity, cornerRadius)Paint with color tint overlay and opacity. Result is cached.

Shape Clip Methods

MethodShape
PaintInCircle(g, cx, cy, radius, imagePath, tint?, opacity)Circle
PaintInTriangle(g, cx, cy, size, imagePath, rotation, tint?, opacity)Triangle
PaintInStar(g, cx, cy, outer, inner, imagePath, points, rotation, tint?, opacity)N-pointed star
PaintInHexagon(g, cx, cy, size, imagePath, rotation, tint?, opacity)Hexagon
PaintInPentagon(g, cx, cy, size, imagePath, rotation, tint?, opacity)Pentagon
PaintInOctagon(g, cx, cy, size, imagePath, rotation, tint?, opacity)Octagon
PaintInPolygon(g, cx, cy, size, sides, imagePath, rotation, tint?, opacity)Any regular N-gon

Usage Example

protected override void DrawContent(Graphics g)
{
    base.DrawContent(g);

    // Paint avatar image clipped to a circle
    float cx = DrawingRect.X + DrawingRect.Width  / 2f;
    float cy = DrawingRect.Y + DrawingRect.Height / 2f;
    float r  = Math.Min(DrawingRect.Width, DrawingRect.Height) / 2f - 2f;

    StyledImagePainter.PaintInCircle(g, cx, cy, r, ImagePath);

    // Or paint with a blue tint at 80% opacity:
    StyledImagePainter.PaintWithTint(g, _clipPath, ImagePath,
        Color.FromArgb(100, 0, 120, 215), opacity: 0.8f, cornerRadius: 8);
}

FormStyle ↔ BeepControlStyle Mapping

When BeepiFormPro.FormStyle changes, BeepStyling.ApplyFormStyle() calls GetControlStyle(formStyle) to sync all controls inside the form to the same visual system:

FormStyleBeepControlStyleFormStyleBeepControlStyle
ModernModernNordicNordic
MinimalMinimaliOSiOS15
MacOSMacOSBigSurUbuntuUbuntu
FluentFluentKDEKde
MaterialMaterialArcLinuxArcLinux
CartoonCartoonDraculaDracula
ChatBubbleChatBubbleSolarizedSolarized
GlassGlassAcrylicOneDarkOneDark
MetroMetroGruvBoxGruvBox
Metro2Metro2NordNord
GNOMEGnomeTokyoTokyo
NeoMorphismNeumorphismPaperPaper
GlassmorphismGlassmorphismNeonNeon
BrutalistBrutalistHolographicHolographic
RetroRetroTerminalTerminal
CyberpunkCyberpunkShadcnShadcn
MaterialYouMaterialYouRadixUIRadixUI
NextJSNextJSLinearLinear
CustomNone(default)Minimal
Control-only styles (Material3, AntDesign, Fluent2, Windows11Mica, ChakraUI, TailwindCard, DarkGlow, DiscordStyle, GradientModern, Bootstrap, FigmaCard, etc.) have no matching FormStyle and default to FormStyle.Custom in the reverse lookup. They are available for individual controls but cannot be set on the form chrome directly.

BeepControlStyle Enum

60+ styles grouped by origin:

Web Frameworks & Design Systems

Material3, AntDesign, Fluent2, MaterialYou, Windows11Mica, MacOSBigSur, ChakraUI, TailwindCard, NotionMinimal, VercelClean, StripeDashboard, Bootstrap, FigmaCard, PillRail, Apple, Shadcn, RadixUI, NextJS, Linear

Dark / Atmospheric

DarkGlow, DiscordStyle, GradientModern, GlassAcrylic, Neumorphism, Glassmorphism, NeoMorphism, Neon, NeonGlow, DarkGlow, Holographic, Cyberpunk

Desktop OS

Minimal, Modern, Fluent, Material, Metro, Metro2, MacOS, iOS15, Ubuntu, Gnome, Kde, Cinnamon, Elementary, ArcLinux, Nordic, Nord

Editor / Terminal Themes

Dracula, Solarized, OneDark, GruvBox, Tokyo, Terminal, Paper

Visual Aesthetics

Cartoon, ChatBubble, Retro, Brutalist, NeoBrutalist, Gaming, HighContrast, Office, FinSet, WebFramework, Effect

Best Practices

  • Never copy-paste style values into a control. Always ask StyleColors, StyleBorders, etc. so the control automatically stays correct when the design system evolves.
  • Let BeepStyling route painter calls; don't call individual painters directly from controls. The routing switch in BeepStyling.PaintStyleBackground() is the single maintenance point for adding new styles.
  • Always set BeepStyling.CurrentTheme whenever BeepThemesManager.CurrentTheme changes. BeepiFormPro.ApplyTheme() does this automatically; your custom root forms must do the same.
  • Use PainterKind = BaseControlPainterKind.None only when the control is doing fully custom rendering. Anything set to None bypasses the shadow, border, and background system entirely.
  • Keep painters stateless. All context (style, theme, focus state) must come in as method parameters. Painters must not cache mutable state between calls.
  • Use StyledImagePainter for every image draw operation. It handles icon loading, SVG fallback paths, DPI-aware sizing, and the shared cache. Do not call g.DrawImage() with an unconditional Image.FromFile() inside OnPaint.
  • Call InvalidateLayout() after property changes that affect size. For BeepiFormPro, this clears the cached border path and hit areas so the painter recalculates on the next paint cycle.
  • Implement IFormPainter for custom form skins. Register it in PaintersFactory.CreatePainter() under a new FormStyle value. That is the only change required system-wide.