9.1 KiB
Telegram Desktop UI Styling
Style Definition Files
UI element styles (colors, fonts, paddings, margins, icons, etc.) are defined in .style
files using a custom syntax. These files are located alongside the C++ source files they correspond to within specific UI component directories (e.g., Telegram/SourceFiles/ui/chat/chat.style
).
Definitions from other .style
files can be included using the using
directive at the top of the file:
using "ui/basic.style";
using "ui/widgets/widgets.style";
The central definition of named colors happens in Telegram/SourceFiles/ui/colors.palette
. This file allows for theme generation and loading colors from various sources.
Syntax Overview
-
Built-in Types: The syntax recognizes several base types inferred from the value assigned:
int
: Integer numbers (e.g.,lineHeight: 20;
)bool
: Boolean values (e.g.,useShadow: true;
)pixels
: Pixel values, ending withpx
(e.g.,borderWidth: 1px;
). Generated asint
in C++.color
: Named colors defined incolors.palette
(e.g.,background: windowBg;
)icon
: Defined inline using a specific syntax (see below). Generatesstyle::icon
.margins
: Four pixel values for margins or padding. Requiresmargins(top, right, bottom, left)
syntax (e.g.,margin: margins(10px, 5px, 10px, 5px);
orpadding: margins(8px, 8px, 8px, 8px);
). Generatesstyle::margins
(an alias forQMargins
).size
: Two pixel values for width and height (e.g.,iconSize: size(16px, 16px);
). Generatesstyle::size
.point
: Two pixel values for x and y coordinates (e.g.,textPos: point(5px, 2px);
). Generatesstyle::point
.align
: Alignment keywords (e.g.,textAlign: align(center);
oriconAlign: align(left);
). Generatesstyle::align
.font
: Font definitions (e.g.,font: font(14px semibold);
). Generatesstyle::font
.double
: Floating point numbers (e.g.,disabledOpacity: 0.5;
)
Note on Borders: Borders are typically defined using multiple fields like
border: pixels;
(for width) andborderFg: color;
(for color), rather than a single CSS-like property. -
Structure Definition: You can define complex data structures directly within the
.style
file:MyButtonStyle { // Defines a structure named 'MyButtonStyle' textPadding: margins; // Field 'textPadding' expects margins type icon: icon; // Field 'icon' of type icon height: pixels; // Field 'height' of type pixels }
This generates a
struct MyButtonStyle { ... };
inside thenamespace style
. Fields will have corresponding C++ types (style::margins
,style::icon
,int
). -
Variable Definition & Inheritance: Variables are defined using
name: value;
orgroupName { ... }
. They can be of built-in types or custom structures. Structures can be initialized inline or inherit from existing variables.Icon Definition Syntax: Icons are defined inline using the
icon{...}
syntax. The generator probes for.svg
files or.png
files (including@2x
,@3x
variants) based on the provided path stem.// Single-part icon definition: myIconSearch: icon{{ "gui/icons/search", iconColor }}; // Multi-part icon definition (layers drawn bottom-up): myComplexIcon: icon{ { "gui/icons/background", iconBgColor }, { "gui/icons/foreground", iconFgColor } }; // Icon with path modifiers (PNG only for flips, SVG only for size): myFlippedIcon: icon{{ "gui/icons/arrow-flip_horizontal", arrowColor }}; myResizedIcon: icon{{ "gui/icons/logo-128x128", logoColor }}; // Forces 128x128 for SVG
Other Variable Examples:
// Simple variables buttonHeight: 30px; activeButtonColor: buttonBgActive; // Named color from colors.palette // Variable of a custom structure type, initialized inline defaultButton: MyButtonStyle { textPadding: margins(10px, 15px, 10px, 15px); // Use margins(...) syntax icon: myIconSearch; // Assign the previously defined icon variable height: buttonHeight; // Reference another variable } // Another variable inheriting from 'defaultButton' and overriding/adding fields primaryButton: MyButtonStyle(defaultButton) { icon: myComplexIcon; // Override icon with the multi-part one backgroundColor: activeButtonColor; // Add a field not in MyButtonStyle definition } // Style group (often used for specific UI elements) chatInput { // Example using separate border properties and explicit padding border: 1px; // Border width borderFg: defaultInputFieldBorder; // Border color (named color) padding: margins(5px, 10px, 5px, 10px); // Use margins(...) syntax for padding field backgroundColor: defaultChatBg; // Background color }
Code Generation
A code generation tool processes these .style
files and colors.palette
to create C++ objects.
- The
using
directives resolve dependencies between.style
files. - Custom structure definitions (like
MyButtonStyle
) generate correspondingstruct MyButtonStyle { ... };
within thenamespace style
. - Style variables/groups (like
defaultButton
,primaryButton
,chatInput
) are generated as objects/structs within thest
namespace (e.g.,st::defaultButton
,st::primaryButton
,st::chatInput
). These generated structs contain members corresponding to the fields defined in the.style
file. - Color objects are generated into the
st
namespace as well, based on their names incolors.palette
(e.g.,st::windowBg
,st::buttonBgActive
). - The generated header files for styles are placed in the
Telegram/SourceFiles/styles/
directory with astyle_
prefix (e.g.,styles/style_widgets.h
forui/widgets/widgets.style
). You include them like#include "styles/style_widgets.h"
.
Generated C++ types correspond to the .style
types: style::color
, style::font
, style::margins
(used for both margin:
and padding:
fields), style::icon
, style::size
, style::point
, style::align
, and int
or bool
for simple types.
Style Usage in Code
Styles are applied in C++ code by referencing the generated st::...
objects and their members.
// Example: Including the generated style header
#include "styles/style_widgets.h" // For styles defined in ui/widgets/widgets.style
// ... inside some UI class code ...
// Accessing members of a generated style struct
int height = st::primaryButton.height; // Accessing the 'height' field (pixels -> int)
const style::icon &icon = st::primaryButton.icon; // Accessing the 'icon' field (st::myComplexIcon)
style::margins padding = st::primaryButton.textPadding; // Accessing 'textPadding'
style::color bgColor = st::primaryButton.backgroundColor; // Accessing the color (st::activeButtonColor)
// Applying styles (conceptual examples)
myButton->setIcon(st::primaryButton.icon);
myButton->setHeight(st::primaryButton.height);
myButton->setPadding(st::primaryButton.textPadding);
myButton->setBackgroundColor(st::primaryButton.backgroundColor);
// Using styles directly in painting
void MyWidget::paintEvent(QPaintEvent *e) {
Painter p(this);
p.fillRect(rect(), st::chatInput.backgroundColor); // Use color from chatInput style
// Border painting requires width and color
int borderWidth = st::chatInput.border; // Access border width (pixels -> int)
style::color borderColor = st::chatInput.borderFg; // Access border color
if (borderWidth > 0) {
p.setPen(QPen(borderColor, borderWidth));
// Adjust rect for pen width if needed before drawing
p.drawRect(rect().adjusted(borderWidth / 2, borderWidth / 2, -borderWidth / 2, -borderWidth / 2));
}
// Access padding (style::margins)
style::margins inputPadding = st::chatInput.padding;
// ... use inputPadding.top(), inputPadding.left() etc. for content layout ...
}
Key Points:
- Styles are defined in
.style
files next to their corresponding C++ source files. using "path/to/other.style";
includes definitions from other style files.- Named colors are defined centrally in
ui/colors.palette
. .style
syntax supports built-in types (likepixels
,color
,margins
,point
,size
,align
,font
,double
), custom structure definitions (Name { field: type; ... }
), variable definitions (name: value;
), and inheritance (child: Name(parent) { ... }
).- Values must match the expected type (e.g., fields declared as
margins
type, likemargin:
orpadding:
, requiremargins(...)
syntax). Borders are typically set via separateborder: pixels;
andborderFg: color;
fields. - Icons are defined inline using
name: icon{{ "path_stem", color }};
orname: icon{ { "path1", c1 }, ... };
syntax, with optional path modifiers. - Code generation creates
struct
definitions in thestyle
namespace for custom types and objects/structs in thest
namespace for defined variables/groups. - Generated headers are in
styles/
with astyle_
prefix and must be included. - Access style properties via the generated
st::
objects (e.g.,st::primaryButton.height
,st::chatInput.backgroundColor
).