[TOC]
Key Features • Installation • How To Use • Code Architecture • Credits • License
NOTE: Currently, only Linux with the X11 Window System is supported.
- Declarative - Or as close as it can get with c++ syntax and macros
- Event Driven - Built-in event bus extensible with custom events
- Component Oriented - Declare encapsulated components and reuse them anywhere
- Header-only UIs - A single component in a header file is renderable UI
- Reactive sizing of components - Relations can be established between different dimensions
- Multi-threaded - Separate event and render threads as well as a custom task runner
- Better abstraction for component styling
- Integrate with CSS (or similar)
- Cross-platform
- Windows, macOS and Linux ready.
Everything needed in order to use this library is located inside dist/
, header files to be included in the project are in dist/include
.
Make sure the binary dist/libcyd_ui.a
is linked to the project and that the header files are included:
# ...
include_directories(<PATH TO HEADER FILES DIRECTORY>)
target_link_libraries(<EXECUTABLE> PUBLIC <PATH TO BINARY libcyd_ui.a>)
Any project using this library must also link against the following libraries:
- X11
- Xft
- Xrender
- fontconfig
- yaml-cpp
- jpeg
# ...
# On some systems, it may be needed to include the headers directory
# for freetype2. On Arch Linux: /usr/include/freetype2
include_directories(<PATH TO FREETYPE2 HEADERS>)
target_link_libraries(<EXECUTABLE> PUBLIC X11 Xft Xrender)
target_link_libraries(<EXECUTABLE> PUBLIC fontconfig)
target_link_libraries(<EXECUTABLE> PUBLIC yaml-cpp)
target_link_libraries(<EXECUTABLE> PUBLIC jpeg)
Each component must have a declaration for a state class and a component class. This is done with the STATE(NAME){}
and COMPONENT(NAME){}
macros.
The name must be a valid class name.
This example declares a component that displays an orange rectangle with black text inside. A third component is added 40 pixels down from the top.
// SomeComponent.hpp
#include "cydui.hpp"
// Declare STATE class for component
// This one persists across renders
STATE(SomeComponent) { // Expands to 'SomeComponentState'
// Color instances
color::Color fg_color = "#FCAE1E"_color;
color::Color fg_inv_color = "#000000"_color;
// Font specification
font::Font font {
.name = "Fira Code Retina",
.size = 10,
};
INIT_STATE(SomeComponent) {
// Optional initialization code...
}
};
// Declare COMPONENT class for component
// This one may be created or destroyed at any moment
// In general, if it's not on screen it's not here either
COMPONENT(SomeComponent) {
PROPS({ // Passed from parent on each render
std::string label;
})
INIT(SomeComponent) {
// Optional initialization code...
}
REDRAW {
// Declare contents of this component
// 'props' Holds the properties for this render as the type declared
// above with PROPS({...}).
// 'state' Is a reference to the relevant SomeComponentState instance.
// 'dim' Contains the dimensions of this instance of SomeComponent.
// x/y - position relative to parent
// cx/cy - absolute position relative to top-left corner of the window
// w/h - absolute size
// cw/ch - content size, accounting for padding and margin
add({
COMP(Rectangle)({
.props = { // Set properties of children component
.color = state->fg_color, //
.filled = true, //
},
.w = dim->cw, // Set dimensional relations (x,y,w,h)
.h = state->font.size * 2, //
}),
COMP(Text)({
.props = {
.color = state->fg_inv_color,
.font = &state->font,
.text = props.label,
},
.y = state->font.size / 2,
// Optionally, you can provide an initialization function
.init = [this](Text* text) {
text->dim->x = dim->cw + (-1 * text->dim->w) - 5;
},
}),
COMP(OtherComponent)({
.props = {
.label = "Hello there..."
},
.x = 3,
.y = 40,
}),
});
// Rectangle and Text are Component primitives included in the library
// OtherComponent would be another component declared similar to SomeComponent
}
};
In order to show the component on the screen, it must be instantiated along with its state. Then a layout is created with the component as the root. Finally, a window is constructed.
// main.cpp
#include "SomeComponent.hpp"
int main() {
// Instantiate a layout to hold the root component and handle events
cydui::layout::Layout* layout = cydui::layout::create<SomeComponent>({
.props = {
.label = "Hello, World!",
},
});
// Create the window that will display the layout
cydui::window::CWindow* win = cydui::window::create(
layout,
"Example Window Title",
"example-window-class",
0, 0, // X, Y of the window
800, 800 // W, H of the window
);
// Hold main thread in a loop of do something else...
//while (1);
return 0;
}
This will start the window on a separate thread.
This software uses the following open source projects:
GPL 3.0
GitHub @castle055 ·