- Remove outdated `undo-state.md` - Add two code quality/optimization reports that were used to guide previous work: - `code-report.md` (optimization) - `code-report-quality.md` (stability and code health) - Add `themes.md`. - Update undo system docs and roadmap.
512 lines
14 KiB
Markdown
512 lines
14 KiB
Markdown
Themes in kte
|
|
=============
|
|
|
|
Overview
|
|
--------
|
|
|
|
kte's GUI frontend (kge) uses ImGui for rendering and supports multiple
|
|
color themes. Themes define the visual appearance of the editor
|
|
interface including colors for text, backgrounds, buttons, borders, and
|
|
other UI elements.
|
|
|
|
Theme files are located in the `themes/` directory and are header-only
|
|
C++ files that configure ImGui's style system.
|
|
|
|
Available themes
|
|
----------------
|
|
|
|
Current themes (alphabetically):
|
|
|
|
- **amber** — Monochrome amber/black CRT-inspired theme
|
|
- **eink** — E-ink inspired high-contrast theme (light/dark variants)
|
|
- **everforest** — Warm, forest-inspired palette
|
|
- **gruvbox** — Retro groove color scheme (light/dark variants)
|
|
- **kanagawa-paper** — Inspired by traditional Japanese art
|
|
- **lcars** — Star Trek LCARS interface style
|
|
- **nord** — Arctic, north-bluish color palette
|
|
- **old-book** — Sepia-toned vintage book aesthetic (light/dark
|
|
variants)
|
|
- **orbital** — Space-themed dark palette
|
|
- **plan9** — Minimalist Plan 9 from Bell Labs inspired
|
|
- **solarized** — Ethan Schoonover's Solarized (light/dark variants)
|
|
- **weyland-yutani** — Alien franchise corporate aesthetic
|
|
- **zenburn** — Low-contrast, easy-on-the-eyes theme
|
|
|
|
Configuration
|
|
-------------
|
|
|
|
Themes are configured via `$HOME/.config/kte/kge.ini`:
|
|
|
|
```ini
|
|
theme = nord
|
|
background = dark
|
|
```
|
|
|
|
- `theme` — The theme name (e.g., "nord", "gruvbox", "solarized")
|
|
- `background` — Either "dark" or "light" (for themes supporting both
|
|
variants)
|
|
|
|
Themes can also be switched at runtime using the `:theme <name>`
|
|
command.
|
|
|
|
Theme structure
|
|
---------------
|
|
|
|
Each theme is a header file in `themes/` that defines one or more
|
|
functions to apply the theme. The basic structure:
|
|
|
|
1. **Include ThemeHelpers.h** — Provides the `RGBA()` helper function
|
|
2. **Define palette** — Create `ImVec4` color constants using
|
|
`RGBA(0xRRGGBB)`
|
|
3. **Get ImGui style** — Obtain reference via `ImGui::GetStyle()`
|
|
4. **Set style parameters** — Configure padding, rounding, border sizes,
|
|
etc.
|
|
5. **Assign colors** — Map palette to `ImGuiCol_*` enum values
|
|
|
|
### Minimal example structure
|
|
|
|
```cpp
|
|
// themes/MyTheme.h
|
|
#pragma once
|
|
#include "ThemeHelpers.h"
|
|
|
|
static void
|
|
ApplyMyTheme()
|
|
{
|
|
// 1. Define color palette
|
|
const ImVec4 bg = RGBA(0x1e1e1e);
|
|
const ImVec4 fg = RGBA(0xd4d4d4);
|
|
const ImVec4 accent = RGBA(0x007acc);
|
|
|
|
// 2. Get style reference
|
|
ImGuiStyle &style = ImGui::GetStyle();
|
|
|
|
// 3. Set style parameters
|
|
style.WindowPadding = ImVec2(8.0f, 8.0f);
|
|
style.FrameRounding = 3.0f;
|
|
style.WindowBorderSize = 1.0f;
|
|
// ... additional style parameters
|
|
|
|
// 4. Assign colors
|
|
ImVec4 *colors = style.Colors;
|
|
colors[ImGuiCol_Text] = fg;
|
|
colors[ImGuiCol_WindowBg] = bg;
|
|
colors[ImGuiCol_Button] = accent;
|
|
// ... additional color assignments
|
|
}
|
|
```
|
|
|
|
The RGBA() helper
|
|
-----------------
|
|
|
|
The `RGBA()` function (defined in `themes/ThemeHelpers.h`) converts
|
|
packed RGB hex values to ImGui's `ImVec4` format:
|
|
|
|
```cpp
|
|
const ImVec4 color = RGBA(0xRRGGBB); // Opaque (alpha = 1.0)
|
|
const ImVec4 color = RGBA(0xRRGGBB, 0.5f); // With custom alpha
|
|
```
|
|
|
|
Examples:
|
|
|
|
```cpp
|
|
const ImVec4 white = RGBA(0xFFFFFF);
|
|
const ImVec4 black = RGBA(0x000000);
|
|
const ImVec4 red = RGBA(0xFF0000);
|
|
const ImVec4 blue = RGBA(0x0000FF);
|
|
const ImVec4 semi = RGBA(0x808080, 0.5f); // 50% transparent gray
|
|
```
|
|
|
|
ImGui color elements
|
|
--------------------
|
|
|
|
Themes must define colors for ImGui's UI elements. Key `ImGuiCol_*`
|
|
values:
|
|
|
|
### Text
|
|
|
|
- `ImGuiCol_Text` — Main text color
|
|
- `ImGuiCol_TextDisabled` — Disabled/grayed-out text
|
|
- `ImGuiCol_TextSelectedBg` — Text selection background
|
|
|
|
### Windows and backgrounds
|
|
|
|
- `ImGuiCol_WindowBg` — Window background
|
|
- `ImGuiCol_ChildBg` — Child window background
|
|
- `ImGuiCol_PopupBg` — Popup window background
|
|
|
|
### Borders
|
|
|
|
- `ImGuiCol_Border` — Border color
|
|
- `ImGuiCol_BorderShadow` — Border shadow (often transparent)
|
|
|
|
### Frames (input fields, etc.)
|
|
|
|
- `ImGuiCol_FrameBg` — Frame background (normal state)
|
|
- `ImGuiCol_FrameBgHovered` — Frame background when hovered
|
|
- `ImGuiCol_FrameBgActive` — Frame background when active/clicked
|
|
|
|
### Title bars
|
|
|
|
- `ImGuiCol_TitleBg` — Title bar (unfocused)
|
|
- `ImGuiCol_TitleBgActive` — Title bar (focused)
|
|
- `ImGuiCol_TitleBgCollapsed` — Collapsed title bar
|
|
|
|
### Interactive elements
|
|
|
|
- `ImGuiCol_Button` — Button background
|
|
- `ImGuiCol_ButtonHovered` — Button when hovered
|
|
- `ImGuiCol_ButtonActive` — Button when pressed
|
|
- `ImGuiCol_CheckMark` — Checkmark/radio button indicator
|
|
- `ImGuiCol_SliderGrab` — Slider grab handle
|
|
- `ImGuiCol_SliderGrabActive` — Slider grab when dragging
|
|
|
|
### Headers and separators
|
|
|
|
- `ImGuiCol_Header` — Header (tree nodes, collapsing headers)
|
|
- `ImGuiCol_HeaderHovered` — Header when hovered
|
|
- `ImGuiCol_HeaderActive` — Header when clicked
|
|
- `ImGuiCol_Separator` — Separator line
|
|
- `ImGuiCol_SeparatorHovered` — Separator when hovered
|
|
- `ImGuiCol_SeparatorActive` — Separator when dragged
|
|
|
|
### Scrollbars
|
|
|
|
- `ImGuiCol_ScrollbarBg` — Scrollbar background
|
|
- `ImGuiCol_ScrollbarGrab` — Scrollbar grab
|
|
- `ImGuiCol_ScrollbarGrabHovered` — Scrollbar grab when hovered
|
|
- `ImGuiCol_ScrollbarGrabActive` — Scrollbar grab when dragging
|
|
|
|
### Tabs
|
|
|
|
- `ImGuiCol_Tab` — Tab (inactive)
|
|
- `ImGuiCol_TabHovered` — Tab when hovered
|
|
- `ImGuiCol_TabActive` — Tab (active)
|
|
- `ImGuiCol_TabUnfocused` — Tab in unfocused window
|
|
- `ImGuiCol_TabUnfocusedActive` — Active tab in unfocused window
|
|
|
|
### Tables
|
|
|
|
- `ImGuiCol_TableHeaderBg` — Table header background
|
|
- `ImGuiCol_TableBorderStrong` — Strong table borders
|
|
- `ImGuiCol_TableBorderLight` — Light table borders
|
|
- `ImGuiCol_TableRowBg` — Table row background
|
|
- `ImGuiCol_TableRowBgAlt` — Alternating table row background
|
|
|
|
### Navigation and overlays
|
|
|
|
- `ImGuiCol_MenuBarBg` — Menu bar background
|
|
- `ImGuiCol_ResizeGrip` — Resize grip indicator
|
|
- `ImGuiCol_ResizeGripHovered` — Resize grip when hovered
|
|
- `ImGuiCol_ResizeGripActive` — Resize grip when dragging
|
|
- `ImGuiCol_DragDropTarget` — Drag-and-drop target highlight
|
|
- `ImGuiCol_NavHighlight` — Navigation highlight
|
|
- `ImGuiCol_NavWindowingHighlight` — Window navigation highlight
|
|
- `ImGuiCol_NavWindowingDimBg` — Window navigation dim background
|
|
- `ImGuiCol_ModalWindowDimBg` — Modal window dim background
|
|
|
|
### Plots (graphs)
|
|
|
|
- `ImGuiCol_PlotLines` — Plot line color
|
|
- `ImGuiCol_PlotLinesHovered` — Plot line when hovered
|
|
- `ImGuiCol_PlotHistogram` — Histogram color
|
|
- `ImGuiCol_PlotHistogramHovered` — Histogram when hovered
|
|
|
|
Style parameters
|
|
----------------
|
|
|
|
In addition to colors, themes can customize style parameters:
|
|
|
|
```cpp
|
|
ImGuiStyle &style = ImGui::GetStyle();
|
|
|
|
// Padding and spacing
|
|
style.WindowPadding = ImVec2(8.0f, 8.0f); // Window content padding
|
|
style.FramePadding = ImVec2(6.0f, 4.0f); // Frame (input fields) padding
|
|
style.CellPadding = ImVec2(6.0f, 4.0f); // Table cell padding
|
|
style.ItemSpacing = ImVec2(6.0f, 6.0f); // Space between items
|
|
style.ItemInnerSpacing = ImVec2(6.0f, 4.0f); // Space within composite items
|
|
|
|
// Rounding
|
|
style.WindowRounding = 4.0f; // Window corner rounding
|
|
style.FrameRounding = 3.0f; // Frame corner rounding
|
|
style.PopupRounding = 4.0f; // Popup corner rounding
|
|
style.GrabRounding = 3.0f; // Grab handle rounding
|
|
style.TabRounding = 4.0f; // Tab corner rounding
|
|
|
|
// Borders
|
|
style.WindowBorderSize = 1.0f; // Window border width
|
|
style.FrameBorderSize = 1.0f; // Frame border width
|
|
|
|
// Scrollbars
|
|
style.ScrollbarSize = 14.0f; // Scrollbar width
|
|
style.GrabMinSize = 10.0f; // Minimum grab handle size
|
|
```
|
|
|
|
Creating a new theme
|
|
--------------------
|
|
|
|
Follow these steps to add a new theme to kte:
|
|
|
|
### 1. Create the theme file
|
|
|
|
Create a new header file in `themes/` (e.g., `themes/MyTheme.h`):
|
|
|
|
```cpp
|
|
// themes/MyTheme.h — Brief description
|
|
#pragma once
|
|
#include "ThemeHelpers.h"
|
|
|
|
// Expects to be included from GUITheme.h after <imgui.h> and RGBA() helper
|
|
|
|
static void
|
|
ApplyMyTheme()
|
|
{
|
|
// Define your color palette
|
|
const ImVec4 background = RGBA(0x1e1e1e);
|
|
const ImVec4 foreground = RGBA(0xd4d4d4);
|
|
const ImVec4 accent = RGBA(0x007acc);
|
|
// ... more colors
|
|
|
|
ImGuiStyle &style = ImGui::GetStyle();
|
|
|
|
// Configure style parameters
|
|
style.WindowPadding = ImVec2(8.0f, 8.0f);
|
|
// ... more style settings
|
|
|
|
ImVec4 *colors = style.Colors;
|
|
|
|
// Assign all required colors
|
|
colors[ImGuiCol_Text] = foreground;
|
|
colors[ImGuiCol_WindowBg] = background;
|
|
// ... assign all other ImGuiCol_* values
|
|
}
|
|
```
|
|
|
|
Refer to existing themes like `Nord.h` for a complete example of all
|
|
required color assignments.
|
|
|
|
### 2. Add theme to GUITheme.h
|
|
|
|
Edit `GUITheme.h` to integrate your theme:
|
|
|
|
**a) Add to ThemeId enum:**
|
|
|
|
```cpp
|
|
enum class ThemeId {
|
|
// ... existing themes
|
|
MyTheme = 13, // Use next available number
|
|
};
|
|
```
|
|
|
|
**b) Include your theme header:**
|
|
|
|
```cpp
|
|
// After other theme includes
|
|
#include "themes/MyTheme.h"
|
|
```
|
|
|
|
**c) Create wrapper class in detail namespace:**
|
|
|
|
```cpp
|
|
namespace detail {
|
|
// ... existing theme classes
|
|
|
|
struct MyThemeWrapper final : Theme {
|
|
[[nodiscard]] const char *Name() const override
|
|
{
|
|
return "mytheme"; // Lowercase canonical name
|
|
}
|
|
|
|
void Apply() const override
|
|
{
|
|
ApplyMyTheme();
|
|
}
|
|
|
|
ThemeId Id() override
|
|
{
|
|
return ThemeId::MyTheme;
|
|
}
|
|
};
|
|
} // namespace detail
|
|
```
|
|
|
|
**d) Register in ThemeRegistry():**
|
|
|
|
```cpp
|
|
static const std::vector<std::unique_ptr<Theme>> &
|
|
ThemeRegistry()
|
|
{
|
|
static std::vector<std::unique_ptr<Theme>> reg;
|
|
if (reg.empty()) {
|
|
// Add in alphabetical order by canonical name
|
|
reg.emplace_back(std::make_unique<detail::AmberTheme>());
|
|
// ... existing themes
|
|
reg.emplace_back(std::make_unique<detail::MyThemeWrapper>());
|
|
// ... remaining themes
|
|
}
|
|
return reg;
|
|
}
|
|
```
|
|
|
|
### 3. Test your theme
|
|
|
|
Rebuild kte and test:
|
|
|
|
```bash
|
|
# Set theme in config
|
|
echo "theme = mytheme" >> ~/.config/kte/kge.ini
|
|
|
|
# Or switch at runtime
|
|
kge
|
|
:theme mytheme
|
|
```
|
|
|
|
Light/Dark theme variants
|
|
--------------------------
|
|
|
|
Some themes support both light and dark background modes. To implement
|
|
this:
|
|
|
|
### 1. Create separate functions for each variant
|
|
|
|
```cpp
|
|
// themes/MyTheme.h
|
|
#pragma once
|
|
#include "ThemeHelpers.h"
|
|
|
|
static void
|
|
ApplyMyThemeDark()
|
|
{
|
|
const ImVec4 bg = RGBA(0x1e1e1e); // Dark background
|
|
const ImVec4 fg = RGBA(0xd4d4d4); // Light text
|
|
// ... rest of dark theme
|
|
}
|
|
|
|
static void
|
|
ApplyMyThemeLight()
|
|
{
|
|
const ImVec4 bg = RGBA(0xffffff); // Light background
|
|
const ImVec4 fg = RGBA(0x1e1e1e); // Dark text
|
|
// ... rest of light theme
|
|
}
|
|
```
|
|
|
|
### 2. Check background mode in Apply()
|
|
|
|
```cpp
|
|
// In GUITheme.h wrapper class
|
|
struct MyThemeWrapper final : Theme {
|
|
// ... Name() and Id() methods
|
|
|
|
void Apply() const override
|
|
{
|
|
if (gBackgroundMode == BackgroundMode::Dark)
|
|
ApplyMyThemeDark();
|
|
else
|
|
ApplyMyThemeLight();
|
|
}
|
|
};
|
|
```
|
|
|
|
See `Solarized.h`, `Gruvbox.h`, `EInk.h`, or `OldBook.h` for complete
|
|
examples.
|
|
|
|
Updating existing themes
|
|
------------------------
|
|
|
|
To modify an existing theme:
|
|
|
|
### 1. Locate the theme file
|
|
|
|
Theme files are in `themes/` directory. For example, Nord theme is in
|
|
`themes/Nord.h`.
|
|
|
|
### 2. Modify colors or style
|
|
|
|
Edit the `ApplyXxxTheme()` function:
|
|
|
|
- Update palette color definitions
|
|
- Change style parameters
|
|
- Reassign `ImGuiCol_*` values
|
|
|
|
### 3. Rebuild and test
|
|
|
|
```bash
|
|
# Rebuild kte
|
|
cmake --build build
|
|
|
|
# Test changes
|
|
./build/kge
|
|
```
|
|
|
|
Changes take effect immediately on next launch or theme switch.
|
|
|
|
Best practices
|
|
--------------
|
|
|
|
When creating or updating themes:
|
|
|
|
1. **Start from an existing theme** — Copy a similar theme as a
|
|
template (e.g., `Nord.h` for dark themes, `Solarized.h` for
|
|
light/dark variants)
|
|
|
|
2. **Define a complete palette first** — Create all color constants at
|
|
the top before assigning them
|
|
|
|
3. **Assign all colors** — Ensure every `ImGuiCol_*` value is set to
|
|
avoid inheriting unexpected colors
|
|
|
|
4. **Use consistent naming** — Follow existing conventions (e.g.,
|
|
`nord0`, `base03`, descriptive names)
|
|
|
|
5. **Test interactivity** — Verify hover, active, and disabled states
|
|
for buttons, frames, and other interactive elements
|
|
|
|
6. **Consider contrast** — Ensure text is readable against backgrounds;
|
|
test with different content
|
|
|
|
7. **Test transparency** — Use alpha values carefully for overlays, dim
|
|
backgrounds, and selection highlights
|
|
|
|
8. **Match style to theme** — Adjust rounding, padding, and borders to
|
|
suit the theme's aesthetic (e.g., sharp corners for retro themes,
|
|
rounded for modern)
|
|
|
|
9. **Document inspiration** — Note the color scheme's origin or
|
|
inspiration in the file header
|
|
|
|
10. **Maintain alphabetical order** — When registering in
|
|
`ThemeRegistry()`, maintain alphabetical order by canonical name
|
|
|
|
Troubleshooting
|
|
---------------
|
|
|
|
### Theme not appearing
|
|
|
|
- Check that the theme is registered in `ThemeRegistry()` in
|
|
alphabetical order
|
|
- Verify the canonical name matches what you're using in config or
|
|
commands
|
|
- Ensure the theme header is included in `GUITheme.h`
|
|
|
|
### Colors look wrong
|
|
|
|
- Verify hex color values are in 0xRRGGBB format (not 0xBBGGRR)
|
|
- Check alpha values for semi-transparent elements
|
|
- Ensure all `ImGuiCol_*` values are assigned
|
|
|
|
### Style inconsistent
|
|
|
|
- Make sure style parameters are set before color assignments
|
|
- Check that you're getting `ImGui::GetStyle()` reference correctly
|
|
- Verify no global style changes are overriding theme settings
|
|
|
|
References
|
|
----------
|
|
|
|
- ImGui style
|
|
reference: https://github.com/ocornut/imgui/blob/master/imgui.h
|
|
- Existing themes in `themes/` directory
|
|
- Color palette resources: coolors.co, colorhunt.co
|