# FTRTabControl

## Overview

`FTRTabControl` is a modern Windows Forms tab control designed for applications that need a more customizable and feature-rich tab interface.

It provides:

* Modern tab styling
* Active, inactive, and hover colors
* Optional rounded tab corners
* Close buttons
* Tab pinning
* Drag-and-drop tab reordering
* Tab badges
* Optional blinking badges
* Per-tab custom colors
* Context-menu commands for managing tabs
* Automatic tooltips for truncated tab titles
* Theme integration
* Saving and restoring tab state

`FTRTabControl` is part of the `FTRControls` library and inherits from the standard Windows Forms `TabControl`.

---

## Requirements

`FTRTabControl` is intended for Windows Forms applications.

Add the `FTRControls` assembly to your project and import the required namespace:

```csharp
using FTRControls;
using System.Drawing;
using System.Windows.Forms;
```

The control can be added either:

1. From the Visual Studio Toolbox, or
2. Programmatically in code.

---

## Basic Usage

The following example creates a tab control and adds two tabs:

```csharp
var tabs = new FTRTabControl();

var dashboardPage = new TabPage("Dashboard");
var settingsPage = new TabPage("Settings");

tabs.TabPages.Add(dashboardPage);
tabs.TabPages.Add(settingsPage);

Controls.Add(tabs);
```

You can also configure the control when creating it:

```csharp
var tabs = new FTRTabControl
{
    ShowCloseButton = true,
    AllowTabReorder = true,
    TabRadius = 6
};

tabs.TabPages.Add(new TabPage("Dashboard"));
tabs.TabPages.Add(new TabPage("Settings"));

Controls.Add(tabs);
```

---

# Tab Appearance

`FTRTabControl` provides several properties for controlling the visual appearance of tabs.

## Tab Colors

| Property                | Description                                                   |
| ----------------------- | ------------------------------------------------------------- |
| `ActiveTabColor`        | Background color of the selected tab.                         |
| `InactiveTabColor`      | Background color of unselected tabs.                          |
| `HoverTabColor`         | Background color displayed when the mouse is over a tab.      |
| `ActiveTextColor`       | Text color of the selected tab.                               |
| `InactiveTextColor`     | Text color of unselected tabs.                                |
| `ActiveLineColor`       | Color of the highlight line displayed below the selected tab. |
| `HeaderBottomLineColor` | Color of the separator line below the tab header.             |
| `TabBorderColor`        | Border color of tab headers.                                  |
| `PageBackColor`         | Background color of the tab pages.                            |
| `CloseButtonColor`      | Color of the close button.                                    |
| `CloseButtonHoverColor` | Close-button color when the mouse is over it.                 |

Example:

```csharp
tabs.ActiveTabColor = Color.White;
tabs.InactiveTabColor = Color.LightGray;
tabs.HoverTabColor = Color.Gainsboro;

tabs.ActiveTextColor = Color.Black;
tabs.InactiveTextColor = Color.DimGray;

tabs.ActiveLineColor = Color.DodgerBlue;
tabs.HeaderBottomLineColor = Color.LightGray;
tabs.TabBorderColor = Color.LightGray;

tabs.PageBackColor = Color.White;

tabs.CloseButtonColor = Color.Gray;
tabs.CloseButtonHoverColor = Color.Red;
```

---

## Rounded Tabs

Use `TabRadius` to control the corner radius of tab headers.

```csharp
tabs.TabRadius = 6;
```

Set the value to `0` for square tabs:

```csharp
tabs.TabRadius = 0;
```

`TabRadius` is a Premium feature and requires an active FTR Controls license.

---

# Showing and Hiding the Tab Header

The tab header can be displayed or hidden using `ShowTabsHeader`.

```csharp
tabs.ShowTabsHeader = true;
```

To hide the tab header:

```csharp
tabs.ShowTabsHeader = false;
```

When the header is hidden, the tab pages remain available but the tab-header area is not displayed.

`ShowTabsHeader` is a Premium feature.

---

# Close Buttons

To display a close button on each tab:

```csharp
tabs.ShowCloseButton = true;
```

The close button is displayed when there is more than one tab.

For example:

```csharp
var tabs = new FTRTabControl
{
    ShowCloseButton = true
};

tabs.TabPages.Add(new TabPage("Home"));
tabs.TabPages.Add(new TabPage("Settings"));
```

## Closing Behavior

The control has several built-in rules:

* The last remaining tab cannot be closed.
* A pinned tab cannot be closed.
* Closing a tab raises the `TabClosing` event before the tab is removed.
* The close operation can be cancelled by the application.

---

# Handling Tab Closing

Use the `TabClosing` event when the application needs to approve or reject a close operation.

```csharp
tabs.TabClosing += (sender, e) =>
{
    if (e.TabPage.Text == "Home")
    {
        e.Cancel = true;
    }
};
```

The event provides:

| Property   | Description                                         |
| ---------- | --------------------------------------------------- |
| `TabIndex` | Index of the tab being closed.                      |
| `TabPage`  | The `TabPage` that is about to be closed.           |
| `Cancel`   | Set to `true` to prevent the tab from being closed. |

### Example: Confirm Before Closing

```csharp
tabs.TabClosing += (sender, e) =>
{
    var result = MessageBox.Show(
        $"Close '{e.TabPage.Text}'?",
        "Confirm",
        MessageBoxButtons.YesNo,
        MessageBoxIcon.Question);

    e.Cancel = result != DialogResult.Yes;
};
```

This allows the application to implement its own confirmation or unsaved-data logic.

---

# Tab Context Menu

Right-clicking a tab provides built-in tab management commands.

The available commands are:

* Close
* Close Others
* Close to the Right
* Close All

The displayed command text can be customized using:

```csharp
tabs.ContextMenuCloseText = "Close";
tabs.ContextMenuCloseOthersText = "Close Other Tabs";
tabs.ContextMenuCloseRightText = "Close Tabs to the Right";
tabs.ContextMenuCloseAllText = "Close All Tabs";
```

The context menu follows the same tab-closing rules as the close button.

For example, pinned tabs cannot be closed through these commands.

---

# Tab Reordering

Enable drag-and-drop reordering with:

```csharp
tabs.AllowTabReorder = true;
```

Users can then drag tabs to change their order.

Example:

```csharp
var tabs = new FTRTabControl
{
    AllowTabReorder = true
};
```

## Reordering Rules

* A pinned tab cannot be dragged.
* A tab cannot be dropped onto a pinned tab.
* The selected tab is updated after a successful reorder.

`AllowTabReorder` is a Premium feature.

---

# Tab Pinning

A tab can be marked as pinned using `SetTabPinned`.

```csharp
tabs.SetTabPinned(page, true);
```

To unpin the tab:

```csharp
tabs.SetTabPinned(page, false);
```

You can check whether a tab is pinned:

```csharp
bool isPinned = tabs.IsTabPinned(page);
```

Example:

```csharp
var dashboard = new TabPage("Dashboard");

tabs.TabPages.Add(dashboard);

tabs.SetTabPinned(dashboard, true);
```

Pinned tabs are visually marked and cannot be:

* Closed
* Dragged to another position

Pinning is intended for tabs that should remain available to the user, such as Home, Dashboard, or other permanent application pages.

---

# Tab Badges

A badge can be displayed on a tab to show a count, status, or other short piece of information.

```csharp
tabs.SetTabBadge(
    page,
    "3",
    Color.Red);
```

The badge text can contain any short string:

```csharp
tabs.SetTabBadge(page, "New", Color.Green);
```

If no color is supplied, the control uses its default badge color.

## Removing a Badge

Pass an empty or null text value:

```csharp
tabs.SetTabBadge(page, null);
```

or:

```csharp
tabs.SetTabBadge(page, "");
```

---

# Setting a Badge by Tab Index

A badge can also be assigned using the tab index:

```csharp
tabs.SetTabBadge(
    0,
    "5",
    Color.Red);
```

This is useful when the application already works with tab indexes rather than `TabPage` references.

---

# Advanced Badges

For badges that need blinking behavior, use `SetTabBadgeAdvanced`.

```csharp
tabs.SetTabBadgeAdvanced(
    page,
    "!",
    Color.Red,
    true);
```

Parameters:

| Parameter    | Description                      |
| ------------ | -------------------------------- |
| `page`       | The tab that receives the badge. |
| `text`       | Badge text.                      |
| `badgeColor` | Badge background color.          |
| `blink`      | Enables or disables blinking.    |

Example:

```csharp
tabs.SetTabBadgeAdvanced(
    page,
    "Alert",
    Color.Red,
    true);
```

Set `blink` to `false` for a normal non-blinking badge.

An empty or null badge text removes the badge.

---

# Custom Color for an Individual Tab

A specific tab can have its own background color:

```csharp
tabs.SetTabColor(page, Color.LightBlue);
```

This overrides the normal active/inactive/hover background colors for that tab.

To remove the custom color and return the tab to the standard color behavior:

```csharp
tabs.SetTabColor(page, Color.Empty);
```

This is useful for highlighting special tabs such as:

* Warnings
* Notifications
* Active workflows
* Important documents
* User-defined categories

---

# Themes

`FTRTabControl` supports the FTR Controls theme system.

The control automatically applies the current application theme.

The following theme modes are supported by the control:

* Light
* Dark
* Duotone
* Color

The control also responds to theme changes while the application is running.

Normally, no additional code is required.

If the application needs to explicitly reapply the current theme, call:

```csharp
tabs.ApplyTheme();
```

---

# Tab Images

Because `FTRTabControl` inherits from the standard Windows Forms `TabControl`, it supports `ImageList` and `ImageIndex`.

Example:

```csharp
var imageList = new ImageList();

imageList.Images.Add("dashboard", dashboardIcon);
imageList.Images.Add("settings", settingsIcon);

tabs.ImageList = imageList;

var page = new TabPage("Dashboard")
{
    ImageIndex = 0
};

tabs.TabPages.Add(page);
```

The image is displayed before the tab title.

---

# Tooltips for Long Tab Titles

If a tab title does not fit within the available tab width, `FTRTabControl` automatically displays the full title in a tooltip when the user moves the mouse over the tab.

No additional configuration is required.

For example, a long title such as:

```text
Customer Account Configuration and Transaction History
```

may be truncated visually while hovering over the tab displays the complete title.

---

# Saving Tab State

`FTRTabControl` can save tab metadata and visual state to a JSON file.

```csharp
tabs.SaveState("tabs.json");
```

The saved state includes information such as:

* Tab name
* Tab caption
* Image index
* Badge text
* Badge color
* Badge blinking state
* Pinned state
* Custom tab color
* Current tab order

Example:

```csharp
private void SaveTabs()
{
    tabs.SaveState("tabs.json");
}
```

## Important

The saved state does **not** contain the actual controls or application content hosted inside each `TabPage`.

It also does not store the currently selected tab.

The state file should therefore be considered a way to persist tab metadata and arrangement, not a complete serialization of the application's UI.

---

# Loading Tab State

Use `LoadState` to restore previously saved tabs.

```csharp
tabs.LoadState(
    "tabs.json",
    () => new TabPage());
```

The second parameter is a callback used to create a new `TabPage` for each saved tab.

A typical application should use the saved tab information to determine what content should be created for the restored tab.

For example:

```csharp
tabs.LoadState(
    "tabs.json",
    () =>
    {
        return new TabPage();
    });
```

The callback must return a valid `TabPage`.

If the callback returns `null`, that tab is skipped during restoration.

---

# Restoring Application-Specific Tab Content

Because `FTRTabControl` stores tab metadata rather than the actual application controls inside a page, applications that use state persistence should make their tab pages recreatable.

For example, an application may associate a page name with a specific type of content:

```csharp
tabs.LoadState(
    "tabs.json",
    () =>
    {
        var page = new TabPage();

        // Create and add the application's controls here.

        return page;
    });
```

The application is responsible for deciding what content belongs inside the restored page.

---

# State File

The state is stored as JSON.

A saved file contains tab information similar to:

```json
{
  "Tabs": [
    {
      "Name": "Dashboard",
      "Text": "Dashboard",
      "ImageIndex": 0,
      "BadgeText": "3",
      "BadgeColor": "-65536",
      "IsPinned": true,
      "CustomColor": null,
      "BadgeBlink": false
    }
  ]
}
```

The exact JSON structure is managed by the control and should not normally be modified manually.

Applications should treat the generated state file as application data.

---

# State Persistence Workflow

A typical application workflow is:

1. Create the `FTRTabControl`.
2. Create and add the application's tabs.
3. Configure badges, pinning, colors, and other settings.
4. Call `SaveState()` when the application needs to persist the tab arrangement.
5. On the next application startup, call `LoadState()`.
6. Provide a callback that creates the appropriate `TabPage` instances.
7. Recreate application-specific content inside those pages.

Example:

```csharp
// Application startup
tabs.LoadState(
    "tabs.json",
    () => new TabPage());

// Application shutdown
tabs.SaveState("tabs.json");
```

For applications with dynamic tab content, the callback should create the appropriate page and its child controls.

---

# Complete Example

The following example demonstrates several customer-facing features together:

```csharp
using System.Drawing;
using System.Windows.Forms;
using FTRControls;

public partial class MainForm : Form
{
    private readonly FTRTabControl tabs;

    public MainForm()
    {
        InitializeComponent();

        tabs = new FTRTabControl
        {
            Dock = DockStyle.Fill,

            ShowCloseButton = true,
            AllowTabReorder = true,

            TabRadius = 6,

            ActiveTabColor = Color.White,
            InactiveTabColor = Color.LightGray,
            HoverTabColor = Color.Gainsboro,

            ActiveTextColor = Color.Black,
            InactiveTextColor = Color.DimGray,

            ActiveLineColor = Color.DodgerBlue,
            HeaderBottomLineColor = Color.LightGray,

            TabBorderColor = Color.LightGray,
            PageBackColor = Color.White,

            CloseButtonColor = Color.Gray,
            CloseButtonHoverColor = Color.Red
        };

        Controls.Add(tabs);

        CreateTabs();
        ConfigureEvents();
    }

    private void CreateTabs()
    {
        var dashboard = new TabPage("Dashboard")
        {
            Name = "Dashboard"
        };

        var notifications = new TabPage("Notifications")
        {
            Name = "Notifications"
        };

        tabs.TabPages.Add(dashboard);
        tabs.TabPages.Add(notifications);

        tabs.SetTabPinned(dashboard, true);

        tabs.SetTabBadge(
            notifications,
            "3",
            Color.Red);
    }

    private void ConfigureEvents()
    {
        tabs.TabClosing += (sender, e) =>
        {
            if (e.TabPage.Name == "Dashboard")
            {
                e.Cancel = true;
                return;
            }

            var result = MessageBox.Show(
                $"Close '{e.TabPage.Text}'?",
                "Confirm",
                MessageBoxButtons.YesNo,
                MessageBoxIcon.Question);

            e.Cancel = result != DialogResult.Yes;
        };
    }
}
```

---

# Public API Reference

## Properties

| Property                     | Description                                   | License  |
| ---------------------------- | --------------------------------------------- | -------- |
| `TabRadius`                  | Controls the corner radius of tab headers.    | Premium  |
| `ShowCloseButton`            | Shows close buttons on tabs.                  | Premium  |
| `AllowTabReorder`            | Enables drag-and-drop tab reordering.         | Premium  |
| `ShowTabsHeader`             | Shows or hides the tab header.                | Premium  |
| `ContextMenuCloseText`       | Text used for the Close command.              | Premium  |
| `ContextMenuCloseOthersText` | Text used for the Close Others command.       | Premium  |
| `ContextMenuCloseRightText`  | Text used for the Close to the Right command. | Premium  |
| `ContextMenuCloseAllText`    | Text used for the Close All command.          | Premium  |
| `ActiveTabColor`             | Selected tab background color.                | Standard |
| `InactiveTabColor`           | Unselected tab background color.              | Standard |
| `HoverTabColor`              | Hovered tab background color.                 | Standard |
| `ActiveTextColor`            | Selected tab text color.                      | Standard |
| `InactiveTextColor`          | Unselected tab text color.                    | Standard |
| `ActiveLineColor`            | Selected-tab indicator color.                 | Standard |
| `HeaderBottomLineColor`      | Header separator-line color.                  | Standard |
| `PageBackColor`              | Tab page background color.                    | Standard |
| `CloseButtonColor`           | Close button color.                           | Standard |
| `CloseButtonHoverColor`      | Close button hover color.                     | Standard |
| `TabBorderColor`             | Tab border color.                             | Standard |

---

# Methods

| Method                                               | Description                                                                |
| ---------------------------------------------------- | -------------------------------------------------------------------------- |
| `ApplyTheme()`                                       | Applies the current FTR Controls theme.                                    |
| `SetTabBadge(TabPage, string, Color?)`               | Adds or updates a normal badge.                                            |
| `SetTabBadge(int, string, Color?)`                   | Adds or updates a badge using the tab index.                               |
| `SetTabBadgeAdvanced(TabPage, string, Color?, bool)` | Adds or updates a badge with optional blinking.                            |
| `SetTabPinned(TabPage, bool)`                        | Pins or unpins a tab.                                                      |
| `IsTabPinned(TabPage)`                               | Returns whether a tab is pinned.                                           |
| `SetTabColor(TabPage, Color)`                        | Sets or clears a custom color for a tab.                                   |
| `SaveState(string)`                                  | Saves tab metadata and visual state to a JSON file.                        |
| `LoadState(string, Func<TabPage>)`                   | Loads saved tab state and recreates tab pages using the supplied callback. |

---

# Events

## `TabClosing`

Raised immediately before a tab is closed.

The operation can be cancelled:

```csharp
tabs.TabClosing += (sender, e) =>
{
    e.Cancel = true;
};
```

The event arguments provide:

* `TabIndex`
* `TabPage`
* `Cancel`

---

# Important Behavior and Limitations

When integrating `FTRTabControl` into an application, keep the following behavior in mind:

### Last Tab

The control does not close the final remaining tab.

### Pinned Tabs

Pinned tabs cannot be closed or reordered.

### Tab State

`SaveState()` stores tab metadata and visual configuration. It does not serialize the controls contained inside the `TabPage`.

### Selected Tab

The selected tab is not stored by `SaveState()` and is not restored automatically by `LoadState()`.

If the application needs to remember the selected tab, it should store that information separately.

### Restoring Pages

The application must provide a `TabPage` through the `LoadState()` callback.

The control does not know how to recreate application-specific page content.

### Tab Alignment

The control is designed to display the tab header at the top. The `Alignment` property is not intended to be changed to another position.

### DPI Scaling

The control automatically adjusts its tab dimensions, fonts, and spacing according to the display DPI.

---

# Licensing

Some features of `FTRTabControl` are Premium features.

Premium features include:

* Rounded tab corners
* Close buttons
* Tab reordering
* Hiding the tab header
* Premium context-menu customization

An active FTR Controls license is required to enable these features.

If a Premium property is changed while the required license is not active, the requested change is not applied and the control may display the license activation prompt.

Standard appearance customization, such as tab colors, does not require the Premium feature activation described above.

---

# Recommended Usage

For a typical production application:

1. Add `FTRTabControl` to the form.
2. Add the required `TabPage` instances.
3. Configure the visual theme and colors.
4. Enable Premium features only when required.
5. Use `TabClosing` to protect important tabs or confirm destructive operations.
6. Use pinning for tabs that should remain available.
7. Use badges for notifications and status indicators.
8. Use `SaveState()` and `LoadState()` when tab arrangement should persist between application sessions.
9. Recreate application-specific page content when loading saved state.
10. Store the selected tab separately if the application needs to restore it.

---

# Quick Reference

```csharp
// Create
var tabs = new FTRTabControl();

// Add a tab
var page = new TabPage("Dashboard");
tabs.TabPages.Add(page);

// Enable Premium features
tabs.ShowCloseButton = true;
tabs.AllowTabReorder = true;
tabs.TabRadius = 6;

// Pin a tab
tabs.SetTabPinned(page, true);

// Add a badge
tabs.SetTabBadge(page, "3", Color.Red);

// Add a blinking badge
tabs.SetTabBadgeAdvanced(
    page,
    "!",
    Color.Red,
    true);

// Set a custom tab color
tabs.SetTabColor(page, Color.LightBlue);

// Handle closing
tabs.TabClosing += (sender, e) =>
{
    // Set e.Cancel = true to prevent closing.
};

// Save state
tabs.SaveState("tabs.json");

// Restore state
tabs.LoadState(
    "tabs.json",
    () => new TabPage());
```

---

# Summary

`FTRTabControl` is intended to provide a modern and customizable tab experience for Windows Forms applications while retaining the familiar `TabControl` programming model.

For most applications, the standard workflow is:

**Create → Add TabPages → Configure Appearance → Add Optional Features → Handle Closing → Save/Restore State**

The control manages the tab presentation and metadata, while the application remains responsible for the actual content and business logic contained inside each tab.
