A declarative, Flutter-inspired widget toolkit for building native UIs in C++.
Chain methods, compose layouts, bind reactive state — write once, run on Windows, Linux, and Android.
Platforms: Windows 10+ · Linux · Android · Compiler: MSVC 2022 / GCC / Clang · Standard: C++20 · Renderer: GDI+ / OpenGL / Cairo / NanoVG
The fastest way to get going is with the Flux CLI — it scaffolds a new project and handles all CMake / build wiring automatically.
Install on Linux:
curl -LO https://github.com/HeyItsBablu/flux-cli/releases/latest/download/flux
chmod +x flux
sudo mv flux /usr/local/bin/Install on Windows: download flux.exe from Releases, place it anywhere, and add that folder to your system PATH.
Create and run your app:
flux create my_app
cd my_app
flux run windows # or: flux run linuxSee the CLI section below for the full command reference.
include(FetchContent)
FetchContent_Declare(flux
GIT_REPOSITORY https://github.com/Rosanchaudhary/flux.git
GIT_TAG v0.1.0
)
FetchContent_MakeAvailable(flux)
target_link_libraries(my_app PRIVATE flux::flux)#include <flux/flux.hpp>
class MyApp : public Widget {
public:
WidgetPtr build() override {
return Scaffold(
AppBar("My App"),
Center(Text("Hello World")));
}
};
WidgetPtr createApp(FluxUI *app) {
return FluxApp(
"My App",
std::make_shared<MyApp>(),
AppTheme::light(),
false, 900, 700, false, false);
}Layout system · Reactive counter
Graph widget · Paint canvas
Photo editor · Logic simulator
Illustrator-style app
- Components
- Display
- Interaction
- Input
- Collection
- Canvas
- State
- Layout
- Structure
- Overlay
- Navigation
- Data
- Media
- Network
- CLI
Base class for all UI components. Override build() to return your widget tree.
class MyApp : public Widget {
public:
WidgetPtr build() override {
return Scaffold(
AppBar("My App"),
Center(Text("Hello World")));
}
};
WidgetPtr createApp(FluxUI *app) {
return FluxApp(
"My App",
std::make_shared<MyApp>(),
AppTheme::light(),
false, 900, 700, false, false);
}| Method | Description |
|---|---|
build() |
Returns the widget tree. Called once at startup — never again on state change |
initState() |
Optional setup hook, called once after construction |
dispose() |
Optional cleanup hook, called on destruction |
Key difference from Flutter:
build()is called once. State changes flow directly to widgets via the observer system — no rebuild is triggered.
The parent owns the state and passes a reference to child widgets.
class CounterDisplay : public Widget {
State<int>& counter;
public:
CounterDisplay(State<int>& counter) : counter(counter) {}
WidgetPtr build() override {
return Column({
Text("Current count:"),
Text(counter),
Text(counter, [](int v) {
return v % 2 == 0 ? "Even" : "Odd";
})
});
}
};
class CounterControls : public Widget {
State<int>& counter;
public:
CounterControls(State<int>& counter) : counter(counter) {}
WidgetPtr build() override {
return Row({
Button("Increment", [this]{ counter++; }),
Button("Decrement", [this]{ counter--; }),
Button("Reset", [this]{ counter.set(0); })
});
}
};
class MyApp : public Widget {
State<int> counter{0};
public:
WidgetPtr build() override {
return Scaffold(
AppBar("Flux App"),
Center(
Column({
std::make_shared<CounterDisplay>(counter),
std::make_shared<CounterControls>(counter)
})
)
);
}
};Converts a State<T>* pointer to State<T>& so it works with all widget APIs.
Text(deref(count))
TextInput("...")->setInputValue(deref(text))
Slider(0, 100, 1)->setValue(deref(value))
Toggle("...")->setValue(deref(enabled))Renders a string of text. Auto-sizes to its content by default.
Text("Hello, world!")
->setFontSize(18)
->setFontWeight(FontWeight::Bold)
->setTextColor(RGB(30, 30, 30));
// Reactive
Text(myState);
Text(count, [](int v){ return "Count: " + std::to_string(v); });
// Full TextStyle
StyledText("Hello", TextStyle{}.setFontSize(20).setBold(true));Factory
| Signature | Description |
|---|---|
Text(string) |
Static text |
Text(State<T>) |
Reactive — auto-updates when state changes |
Text(State<T>, transform) |
Reactive with a custom format function |
StyledText(string, TextStyle) |
Static text with a full TextStyle applied upfront |
Methods
| Method | Type | Description |
|---|---|---|
setText(string) |
string |
Set or change displayed text |
setText(State<T>) |
State | Reactive text binding |
setText(State<T>, transform) |
State + fn | Reactive text with transform |
setFontSize(size) |
int |
Font size in points |
setFontWeight(weight) |
FontWeight |
Normal or Bold |
setFontFamily(family) |
string |
Font family name |
setTextScaleFactor(factor) |
float |
Scales font size (1.0 = normal) |
setTextColor(color) |
Color |
Text color |
setTextColor(State<T>, transform) |
State | Reactive text color |
setHoverTextColor(color) |
Color |
Text color on hover |
setLetterSpacing(spacing) |
float |
Extra space between characters |
setWordSpacing(spacing) |
float |
Extra space between words |
setHeight(h) |
float |
Line height multiplier (1.0 = natural; 1.5 = 50% extra leading) |
setTextAlign(align) |
TextAlign |
Left · Center · Right · Justify · Start · End |
setTextAlignVertical(align) |
TextAlignVertical |
Top · Center · Bottom |
setOverflow(overflow) |
TextOverflow |
Clip · Ellipsis · Fade · Visible |
setSoftWrap(wrap) |
bool |
Word-wrap at boundaries (default true) |
setMaxLines(lines) |
int |
Max visible lines; 0 = unlimited |
setTextDirection(dir) |
TextDirection |
LTR or RTL |
setDecoration(decoration) |
TextDecoration |
Underline, strikethrough, overline |
setDecorationColor(color) |
Color |
Decoration line color |
setDecorationStyle(style) |
TextDecorationStyle |
Solid, dashed, dotted, double, wavy |
setDecorationThickness(t) |
int |
Decoration line thickness |
setShadow(shadow) |
TextShadow |
Single text shadow |
setShadows(shadows) |
vector<TextShadow> |
Multiple text shadows |
clearShadows() |
— | Remove all shadows |
setTextBackground(color) |
Color |
Background painted behind each text line |
clearTextBackground() |
— | Remove per-line background |
setTextStyle(style) |
TextStyle |
Apply a full TextStyle at once |
setPadding(p) |
int |
Uniform padding |
setPaddingH(p) |
int |
Horizontal padding (left + right) |
setPaddingV(p) |
int |
Vertical padding (top + bottom) |
setPaddingLRTB(l, r, t, b) |
int ×4 |
Per-side padding |
setBackgroundColor(color) |
Color |
Widget background fill |
setBorderRadius(r) |
int |
Corner rounding for background |
setWidth(w) |
int |
Fixed widget width |
setWidgetHeight(h) |
int |
Fixed widget height |
setMinWidth(w) |
int |
Minimum width constraint |
Renders a glyph from the FluxIcons icon set.
Icon(FluxIcons::Settings)
Icon(FluxIcons::Menu, 20)
Icon(state, [](bool v) -> FluxIcons::IconGlyph {
return v ? FluxIcons::Check : FluxIcons::Close;
})Factory
| Signature | Description |
|---|---|
Icon(glyph) |
Static glyph at default size (16px) |
Icon(glyph, size) |
Static glyph at explicit size |
Icon(State<T>, transform) |
Reactive glyph — transform maps T to FluxIcons::IconGlyph |
Icon(State<T>, transform, size) |
Reactive glyph at explicit size |
Methods
| Method | Description |
|---|---|
setSize(size) |
Icon size in points |
setColor(color) |
Icon color |
setHoverColor(color) |
Icon color on hover |
setIconFontFamily(family) |
Override icon font |
setGlyph(glyph) |
Set or change glyph (FluxIcons::IconGlyph) |
setGlyph(State<T>, transform) |
Reactive glyph binding |
A 1px horizontal rule that fills available width.
Divider()Horizontal progress indicator with solid or gradient fill.
ProgressBar(0.65)
->setProgressColors({ RGB(33,150,243), RGB(0,200,150) })
->setHeight(8)
->setBorderRadius(4);
ProgressBar()->setValue(progressState);Factory
| Signature | Description |
|---|---|
ProgressBar() |
Progress bar starting at 0.0 |
ProgressBar(value) |
Progress bar with initial fill level (0.0–1.0) |
Methods
| Method | Type | Description |
|---|---|---|
setValue(v) |
double 0–1 |
Static fill level |
setValue(State<double>) |
State | Reactive fill level |
setProgressColors(colors) |
vector<Color> |
Solid or gradient fill |
setBackgroundColor(color) |
Color |
Track background |
setBorderColor(color) |
Color |
Track border |
setBorderWidth(w) |
int |
Border thickness |
setBorderRadius(r) |
int |
Corner rounding |
setHeight(h) |
int |
Bar height (default 12px) |
setWidth(w) |
int |
Fixed width |
OpenGL-rendered chart widget supporting Line, Bar, and Area types.
Graph(500, 300)
->addSeries("Temperature", {22,24,27,23,19}, 1.0f, 0.4f, 0.2f)
->setTitle("Daily Temps")
->setXLabels({"Mon","Tue","Wed","Thu","Fri"});
// Reactive
Graph(600, 300)
->addSeries("CPU", cpuDataState, 0.0f, 1.0f, 0.4f)
->setType(GraphType::Area);Factory
| Signature | Description |
|---|---|
Graph() |
Default 400×300 graph |
Graph(w, h) |
Fixed-size graph |
Methods
| Method | Type | Description |
|---|---|---|
addSeries(label, values, r, g, b) |
string, vector<float> |
Add static data series |
addSeries(label, State<...>, r,g,b) |
State | Reactive series |
bindSeries(idx, State) |
int, State |
Retrofit reactive binding |
setType(type) |
GraphType |
Line · Bar · Area |
setTitle(t) |
string |
Chart title |
setXLabels(labels) |
vector<string> |
X-axis tick labels |
setYRange(min, max) |
float, float |
Manual Y-axis range |
setShowGrid(v) |
bool |
Toggle grid lines |
clearSeries() |
— | Remove all series |
setSize(w, h) |
int, int |
Resize the widget |
Renders an image file with five fit modes. Supports local assets, network URLs, and in-memory buffers. All loading is asynchronous.
// Local asset (async)
AssetImage("photo.jpg")
->setWidth(300)
->setHeight(200)
->setFit(ImageFit::Cover);
// Network image
NetworkImage("https://example.com/photo.jpg")
->setWidth(300)
->setHeight(200);
// In-memory buffer
MemoryImage(myBytes)
->setWidth(300);
// Empty widget — load later
Image()
->setImagePath("photo.jpg")
->setWidth(300);
// Circle avatar
AssetImage("avatar.png")->setWidth(64)->setHeight(64)->setBorderRadius(32);Factory
| Signature | Description |
|---|---|
Image() |
Empty image widget — call setImagePath() or setUrl() to load |
AssetImage(path) |
Load a local file asynchronously |
NetworkImage(url) |
Load from an HTTP/HTTPS URL asynchronously |
NetworkImage(url, postToUI) |
As above; postToUI controls UI-thread dispatch (default true) |
MemoryImage(bytes) |
Decode from a vector<uint8_t> synchronously |
ImageWidget::asset(path) |
Static named constructor — same as AssetImage |
ImageWidget::network(url, postToUI) |
Static named constructor — same as NetworkImage |
ImageWidget::memory(bytes) |
Static named constructor — same as MemoryImage |
ImageFit modes
| Value | Description |
|---|---|
ImageFit::Fill |
Stretch to fill — may distort |
ImageFit::Contain |
Fit inside bounds, letterbox (default) |
ImageFit::Cover |
Fill bounds, crop edges |
ImageFit::None |
Original size, positioned by imageAlignment |
ImageFit::ScaleDown |
Like None but scales down if larger than container |
Methods
| Method | Type | Description |
|---|---|---|
setImagePath(path) |
string |
Load or swap a local file at runtime |
setUrl(url, postToUI) |
string, bool |
Load or swap a network URL at runtime |
loadFromUrl(url, postToUI) |
string, bool |
Explicit async network load |
setFit(mode) |
ImageFit |
Sizing/cropping mode |
setRepeat(repeat) |
ImageRepeat |
NoRepeat · Repeat · RepeatX · RepeatY |
setFilterQuality(quality) |
FilterQuality |
None · Low · Medium · High |
setImageAlignment(alignment) |
Alignment |
Positioning of image within the box (used by None/ScaleDown) |
setTintColor(color) |
Color |
Color overlay blended over the image |
setWidth(w) |
int |
Fixed width |
setHeight(h) |
int |
Fixed height |
setBorderRadius(r) |
int |
Corner rounding |
setPadding(p) |
int |
Inner padding |
setPlaceholderColor(c) |
Color |
Fill shown while loading |
setErrorColor(c) |
Color |
Fill shown on load error |
setLoadingBuilder(fn) |
() -> WidgetPtr |
Custom widget shown while loading |
setErrorBuilder(fn) |
() -> WidgetPtr |
Custom widget shown on error |
Clickable widget with a background. Accepts a text label or a child widget.
Button("Save", [&]{ save(); })
->setBackgroundColor(RGB(76,175,80))
->setBorderRadius(6)
->setPadding(12);
// Widget child
Button(Row({Icon(FluxIcons::Upload), Text("Upload")}), [&]{ upload(); });Factory
| Signature | Description |
|---|---|
Button(text, onClick) |
Text label button |
Button(child, onClick) |
Widget child button |
Methods
| Method | Type | Description |
|---|---|---|
setOnClick(handler) |
ClickHandler |
Click callback |
setChild(widget) |
WidgetPtr |
Replace content widget |
setBackgroundColor(color) |
Color |
Button background |
setHoverBackgroundColor(color) |
Color |
Background on hover |
setTextColor(color) |
Color |
Label text color |
setBorderRadius(r) |
int |
Corner rounding |
setPadding(p) |
int |
Uniform padding |
setPaddingAll(l, t, r, b) |
int ×4 |
Per-side padding |
setWidth(w) |
int |
Fixed width |
setHeight(h) |
int |
Fixed height |
Wraps any widget and attaches pointer/gesture callbacks.
GestureDetector(Card(Text("Click me")))
->setOnTap([&]{ handleTap(); })
->setOnDoubleTap([&]{ handleDouble(); })
->setOnLongPress([&]{ showMenu(); })
->setOnDragUpdate([&](int dx, int dy){ pan(dx, dy); })
->setOnScrollUp([&](int delta){ zoom(delta); });
// Shorthand drag
GestureDetector(myWidget, [&](int dx, int dy){ pan(dx, dy); });Long press fires after 500ms. Double-tap window is 300ms. Drag starts after 5px of movement.
Factory
| Signature | Description |
|---|---|
GestureDetector(child) |
Wraps child with no initial callbacks |
GestureDetector(child, onDrag) |
Shorthand with drag handler |
Callbacks
| Method | Signature | Description |
|---|---|---|
setOnTap |
void() |
Single click |
setOnDoubleTap |
void() |
Two taps within 300ms |
setOnLongPress |
void() |
Press held 500ms |
setOnSecondaryTap |
void() |
Right-click |
setOnHoverEnter |
void() |
Cursor enters bounds |
setOnHoverExit |
void() |
Cursor leaves bounds |
setOnPointerMove |
void(x, y) |
Mouse position while inside |
setOnDragStart |
void() |
Drag threshold exceeded |
setOnDragUpdate |
void(dx, dy) |
Delta since last move |
setOnDragEnd |
void() |
Mouse released after drag |
setOnScrollUp |
void(delta) |
Wheel scrolled up |
setOnScrollDown |
void(delta) |
Wheel scrolled down |
Single-line text field with cursor, scroll, placeholder, and two-way State<string> binding.
TextInput("Enter your name...")
->setInputValue(nameState)
->setWidth(320);| Method | Type | Description |
|---|---|---|
setInputValue(State<string>) |
State | Two-way reactive binding |
setPlaceholder(text) |
string |
Hint shown when empty |
setWidth(w) |
int |
Fixed width |
Multiline text input with scrollbars, line numbers, selection, and clipboard support.
TextArea("Type your message...")
->setInputValue(bodyState)
->setWidth(400)
->setHeight(200)
->setLineNumbers(true);Methods
| Method | Type | Description |
|---|---|---|
setInputValue(State<string>) |
State | Two-way reactive binding |
setPlaceholder(text) |
string |
Hint shown when empty |
setLineNumbers(v) |
bool |
Show line number gutter |
setWordWrap(v) |
bool |
Enable word wrap |
setTabSpaces(n) |
int |
Spaces per Tab key press |
setMaxLength(n) |
int |
Max character count (0 = unlimited) |
setFontSize(s) |
int |
Font size |
setWidth(w) |
int |
Fixed width |
setHeight(h) |
int |
Fixed height |
setFlex(n) |
int |
Flex factor in parent |
setScrollbarSize(s) |
int |
Scrollbar thickness |
setScrollbarColor(c) |
Color |
Idle thumb color |
setScrollbarHoverColor(c) |
Color |
Hover thumb color |
setScrollbarTrackColor(c) |
Color |
Track background |
Keyboard:
Ctrl+Aselect all ·Ctrl+C/X/Vclipboard ·Shift+arrowsextend selection ·PgUp/PgDnpage scroll.
Numeric input with up/down arrow buttons, mouse wheel, and direct keyboard editing.
NumberInput(0.0, 100.0, 1.0)
->setValue(countState)
->setPrefix("$")
->setSuffix(" kg")
->setDecimalPlaces(2)
->setWidth(120);
// Alias
SpinBox(0, 255, 1)->setValue(brightnessState);Factory: NumberInput(min, max, step) · SpinBox(min, max, step)
Methods
| Method | Type | Description |
|---|---|---|
setValue(State<double>) |
State | Two-way double binding |
setValue(State<int>) |
State | Two-way int binding |
setMin(v) |
double |
Minimum value |
setMax(v) |
double |
Maximum value |
setStep(v) |
double |
Increment/decrement step |
setDecimalPlaces(n) |
int |
Decimal digits shown (0 = integer) |
setPrefix(s) |
string |
Text prepended to display value |
setSuffix(s) |
string |
Text appended to display value |
setOnValueChanged(fn) |
void(double) |
Fires on every value change |
setWidth(w) |
int |
Fixed width |
setFlex(n) |
int |
Flex factor in parent |
Keyboard:
↑/↓step ·PgUp/PgDnstep ×10 ·Home/Endjump to min/max ·Entercommit typed value ·Escaperevert.
Horizontal range input with draggable thumb and keyboard support.
Slider(0.0, 100.0, 1.0)
->setValue(volumeState)
->setTrackFillColor(RGB(99,102,241))
->setOnValueChanged([&](double v){ setVolume(v); });Factory: Slider(min, max, step)
Methods
| Method | Type | Description |
|---|---|---|
setValue(State<double>) |
State | Two-way double binding |
setValue(State<int>) |
State | Two-way int binding |
setMinValue(v) |
double |
Range minimum |
setMaxValue(v) |
double |
Range maximum |
setStep(v) |
double |
Snap step size |
setTrackColor(c) |
Color |
Unfilled track color |
setTrackFillColor(c) |
Color |
Filled track color |
setThumbColor(c) |
Color |
Thumb color |
setOnValueChanged(fn) |
void(double) |
Change callback |
setWidth(w) |
int |
Fixed width |
On/off switch with animated thumb and optional label. Binds to State<bool>.
Toggle("Dark mode")
->setValue(darkModeState)
->setTrackOnColor(RGB(99,102,241))
->setOnToggleChanged([&](bool v){ applyTheme(v); });| Method | Type | Description |
|---|---|---|
setValue(State<bool>) |
State | Two-way binding |
setToggled(bool) |
bool |
Set initial state |
setLabel(text) |
string |
Text beside the toggle |
setTrackOnColor(c) |
Color |
Track color when on |
setTrackOffColor(c) |
Color |
Track color when off |
setThumbColor(c) |
Color |
Thumb color |
setOnToggleChanged(fn) |
void(bool) |
Change callback |
Standard checkbox with optional label. Binds to State<bool>.
CheckBox("I agree to the terms")->setInputValue(agreedState);| Signature | Description |
|---|---|
CheckBox(label) |
Checkbox with optional text label |
setInputValue(State<bool>) |
Two-way bool binding |
Mutually-exclusive radio buttons bound to State<string>.
RadioGroupWithOptions({
{"free", "Free tier"},
{"pro", "Pro — $9/mo"},
{"team", "Team — $29/mo"},
})->bindValue(planState)
->setOnSelectionChanged([&](const std::string& v){ changePlan(v); });
// Manual
auto group = RadioGroup();
group->addRadioButton(RadioButton("opt_a", "Option A"));
group->addRadioButton(RadioButton("opt_b", "Option B"));
group->setHorizontal();RadioGroup methods
| Method | Description |
|---|---|
addRadioButton(RadioButtonPtr) |
Add a button to the group |
bindValue(State<string>) |
Two-way selected-value binding |
setSelectedValue(string) |
Set selected value imperatively |
setOnSelectionChanged(fn) |
Callback with newly selected value |
setHorizontal() / setVertical() |
Layout direction |
getSelectedValue() |
Returns current selection |
HSV color picker with saturation/value square, hue bar, optional alpha bar, and hex display.
ColorPicker(RGB(255, 0, 0))
->bindValue(brushColorState)
->setShowAlpha(false)
->setOnColorChanged([&](COLORREF c){ applyColor(c); });Factory: ColorPicker(initialColor)
Methods
| Method | Type | Description |
|---|---|---|
setColor(color) |
COLORREF |
Set color imperatively |
getColor() |
COLORREF |
Read current color |
setShowAlpha(show) |
bool |
Show/hide alpha bar (default true) |
setOnColorChanged(fn) |
void(COLORREF) |
Fired on every color change |
bindValue(State<COLORREF>) |
State | Two-way reactive binding |
Calendar popup for selecting a date. Includes month/year navigation and a year-range picker.
DatePicker()
->setDate(FluxDate::today())
->setPlaceholder("Select a date")
->setOnDateChanged([](FluxDate d) {
std::cout << d.toString("%d %b %Y") << std::endl;
});
// Reactive binding
State<FluxDate> selectedDate(FluxDate{}, app);
DatePicker()->setDate(selectedDate);FluxDate struct
FluxDate d = FluxDate::today(); // today
FluxDate d{2025, 6, 15}; // June 15, 2025
d.toString("%d / %m / %Y"); // "15 / 06 / 2025"
d.isValid(); // true if year/month/day are setMethods
| Method | Type | Description |
|---|---|---|
setDate(FluxDate) |
FluxDate |
Set initial date |
setDate(State<FluxDate>) |
State | Two-way reactive binding |
setPlaceholder(text) |
string |
Text when no date selected |
setDateFormat(fmt) |
string |
strftime-style format string |
setMinDate(date) |
FluxDate |
Disable dates before this |
setMaxDate(date) |
FluxDate |
Disable dates after this |
setOnDateChanged(fn) |
void(FluxDate) |
Fires when a date is picked |
setAccentColor(color) |
Color |
Header, selection, and indicator color |
setWidth(w) |
int |
Fixed width |
Navigation: Click month/year header to open year picker.
◀ ▶arrows navigate months or year ranges.
Button-like widget that opens the native OS file dialog on click.
// Single file open
FilePicker()
->setMode(FilePickerMode::Open)
->addFilter("Images", {"*.png","*.jpg","*.jpeg","*.bmp"})
->addFilter("All files", {"*.*"})
->setDefaultExtension("png")
->bindPath(filePath)
->setOnChanged([](const std::string& path) {
std::cout << "Picked: " << path << "\n";
});
// Save dialog
FilePicker()
->setMode(FilePickerMode::Save)
->setTitle("Export Image")
->setDefaultFilename("output.png")
->addFilter("PNG", {"*.png"})
->bindPath(exportPath)
->setOnChanged([&](const std::string& p){ surface->exportImage(p); });
// Multiple files
FilePicker()
->setMode(FilePickerMode::OpenMultiple)
->addFilter("Images", {"*.png","*.jpg"})
->bindPaths(paths)
->setOnMultiChanged([](const std::vector<std::string>& ps){ ... });
// Folder picker
FilePicker()
->setMode(FilePickerMode::Folder)
->setTitle("Select output folder")
->bindPath(folderPath);FilePickerMode
| Value | Description |
|---|---|
FilePickerMode::Open |
Single file open dialog |
FilePickerMode::OpenMultiple |
Multi-file open dialog |
FilePickerMode::Save |
Save / export dialog |
FilePickerMode::Folder |
Directory picker |
Methods
| Method | Type | Description |
|---|---|---|
setMode(m) |
FilePickerMode |
Dialog type |
setTitle(t) |
string |
Dialog window title |
setDefaultFilename(f) |
string |
Pre-filled filename for Save mode |
setDefaultExtension(e) |
string |
Default file extension |
setInitialDir(d) |
string |
Starting directory |
addFilter(label, exts) |
string, vector<string> |
Add a file type filter |
setFilters(fs) |
vector<FileFilter> |
Replace all filters at once |
bindPath(State<string>) |
State | Two-way binding for single path |
bindPaths(State<vector<string>>) |
State | Two-way binding for multi-path |
setOnChanged(fn) |
void(string) |
Fires on single-file selection |
setOnMultiChanged(fn) |
void(vector<string>) |
Fires on multi-file selection |
setOnCancelled(fn) |
void() |
Fires when dialog is cancelled |
setShowPath(v) |
bool |
Show selected path beside button |
setShowClearBtn(v) |
bool |
Show × button to clear selection |
setPathMaxWidth(w) |
int |
Max width of the path display |
setAccentColor(c) |
Color |
Accent color for focus ring |
setWidth(w) |
int |
Fixed width |
setHeight(h) |
int |
Fixed height |
setFlex(n) |
int |
Flex factor in parent |
open() |
— | Open the dialog programmatically |
clear() |
— | Clear the current selection |
path() |
string |
Currently selected single path |
paths() |
vector<string> |
Currently selected paths (multi mode) |
hasSelection() |
bool |
True if a path is selected |
Linux async: On Linux the dialog runs on a background thread via zenity or kdialog. Dispatch results back to the UI by calling
fluxFilePickerDispatchSDLEvent(e)inside yourSDL_USEREVENThandler.
Scrollable list. Static initializer-list form or reactive State<vector<T>> builder form.
// Static
ListView({
Card(Text("Item A")),
Card(Text("Item B")),
})->setSpacing(8);
// Reactive builder
ListView(contactsState)
->itemBuilder([](int i, const Contact& c) -> WidgetPtr {
return Card(Text(c.name));
})
->separator([]{ return Divider(); })
->setSpacing(8);Factory
| Signature | Description |
|---|---|
ListView({item, item, ...}) |
Static list |
ListView(State<vector<T>>) |
Reactive list |
Methods (both modes)
| Method | Description |
|---|---|
setSpacing(px) |
Gap between items |
setHorizontal(bool) |
Switch to horizontal scroll |
setScrollbarSize(px) |
Scrollbar thickness |
setScrollbarColor(c) |
Idle thumb color |
setScrollbarHoverColor(c) |
Hover thumb color |
setScrollbarActiveColor(c) |
Drag thumb color |
setScrollbarTrackColor(c) |
Track background |
setPadding(px) |
Inner padding (static mode) |
setBackgroundColor(c) |
Background fill (static mode) |
setHeight(h) |
Fixed height (static mode) |
Methods (reactive builder only)
| Method | Description |
|---|---|
itemBuilder(fn) |
Builder (int index, const T&) -> WidgetPtr |
separator(fn) |
Widget inserted between items |
setKeyFn(fn) |
Custom key function for diffing |
Scrollable grid driven by State<vector<T>>.
GridView(photosState)
->columns(3)
->itemBuilder([](int i, const Photo& p) -> WidgetPtr {
return Thumbnail(p);
})
->setSpacing(12);
// Responsive
GridView(itemsState)->columnWidth(200)->itemBuilder(...);| Method | Description |
|---|---|
itemBuilder(fn) |
Builder (int index, const T&) -> WidgetPtr |
columns(n) |
Fixed column count |
columnWidth(px) |
Responsive — derive column count from width |
setSpacing(px) |
Set H and V spacing |
setSpacingH(px) |
Horizontal gap |
setSpacingV(px) |
Vertical gap |
setScrollbarWidth(px) |
Scrollbar thickness |
setScrollbarColor(c) |
Idle thumb color |
setScrollbarHoverColor(c) |
Hover thumb color |
setScrollbarActiveColor(c) |
Drag thumb color |
setScrollbarTrackColor(c) |
Track background |
setKeyFn(fn) |
Custom key function for diffing |
Static fixed-column grid for a known set of children. Non-scrolling.
Grid(3,
Card(Text("A")),
Card(Text("B")),
Card(Text("C"))
)->setSpacing(16);
GridFixedWidth(200, items...);
GridFromList(4, widgetVector);Factory
| Signature | Description |
|---|---|
Grid(columns, widgets...) |
Fixed columns, variadic children |
GridFixedWidth(cellWidth, widgets...) |
Responsive from variadic children |
GridFromList(columns, vector) |
Fixed columns from runtime vector |
GridFixedWidthFromList(cellWidth, vector) |
Responsive from runtime vector |
Methods
| Method | Description |
|---|---|
setColumnCount(n) |
Fixed column count |
setColumnWidth(px) |
Responsive mode |
setSpacing(px) |
Uniform gap |
setSpacingH(px) / setSpacingV(px) |
Per-axis gap |
setCrossAxisAlignment(a) |
Start · Center · End · Stretch |
setMainAxisAlignment(a) |
Start · Center · End |
setPadding(px) |
Uniform padding |
setPaddingAll(l, t, r, b) |
Per-side padding |
setBackgroundColor(c) |
Grid background |
setWidth(w) / setHeight(h) |
Fixed dimensions |
setFlex(n) |
Flex factor in parent |
Vertical stack of collapsible panels.
#include "flux/flux_accordion.hpp"
AccordionPanel p1("Appearance", "Theme & display");
p1.icon = L"\uE771";
p1.expanded = true;
p1.body = Column({
Row({ Text("Dark theme"), Toggle(&darkTheme) })->setSpacing(8),
})->setSpacing(12)->setPadding(8);
auto acc = Accordion({ p1, p2, p3 })
->setSingleExpand(true)
->setAccentColor(RGB(33, 150, 243))
->setOnChanged([](int idx, bool open) { });AccordionPanel struct
AccordionPanel p("Title", "Optional subtitle");
p.icon = L"\uE713";
p.expanded = false;
p.disabled = false;
p.body = myWidget;Methods
| Method | Type | Description |
|---|---|---|
setSingleExpand(v) |
bool |
At most one panel open at a time (default false) |
setOnChanged(fn) |
void(int, bool) |
Fires on every expand/collapse |
expand(idx) |
int |
Expand panel by index |
collapse(idx) |
int |
Collapse panel by index |
toggle(idx) |
int |
Toggle panel by index |
expandAll() |
— | Expand all panels |
collapseAll() |
— | Collapse all panels |
panelAt(idx) |
AccordionPanel* |
Mutable access to a panel |
panelCount() |
int |
Number of panels |
setPanels(panels) |
vector<AccordionPanel> |
Replace all panels at runtime |
setHeaderHeight(h) |
int |
Header row height (default 48px) |
setBodyPadding(p) |
int |
Padding inside body area (default 12px) |
setShowBorder(v) |
bool |
Outer rounded border (default true) |
setShowSeparators(v) |
bool |
Dividers between panels (default true) |
setAccentColor(c) |
Color |
Left bar and active header tint |
setTitleFontSize(s) |
int |
Header title font size |
setWidth(w) |
int |
Fixed width |
setFlex(n) |
int |
Flex factor in parent |
Scrollable hierarchical tree with expand/collapse, single selection, keyboard navigation, and optional indent guide lines.
TreeNode root("Project");
auto &src = root.addChild(TreeNode("src"));
src.expanded = true;
src.addChild(TreeNode("main.cpp"));
auto tv = TreeView(root)
->setOnSelectionChanged([](const TreeNode *n) {
std::cout << n->label << std::endl;
})
->setShowGuideLines(true)
->setFlex(1);
// Multiple roots
auto tv = TreeView({rootA, rootB, rootC});TreeNode struct
TreeNode node("label", "optional-id");
node.expanded = true;
node.disabled = false;
node.icon = L"\uE8B7";
node.userData = &myObj;
node.addChild(TreeNode("child"));
node.expandAll();
node.collapseAll();
node.isLeaf();Methods
| Method | Type | Description |
|---|---|---|
setOnSelectionChanged(fn) |
void(const TreeNode*) |
Fires on click |
setOnNodeExpanded(fn) |
void(const TreeNode*) |
Fires on expand |
setOnNodeCollapsed(fn) |
void(const TreeNode*) |
Fires on collapse |
setOnNodeDoubleClicked(fn) |
void(const TreeNode*) |
Fires on double-click |
setRoots(vector<TreeNode>) |
— | Replace the entire tree at runtime |
selectById(id) |
string |
Select a node by its id field |
expandAll() / collapseAll() |
— | Expand or collapse all nodes |
selectedNode() |
const TreeNode* |
Currently selected node |
setRowHeight(h) |
int |
Row height in pixels (default 28) |
setIndentWidth(w) |
int |
Pixels per depth level (default 20) |
setShowGuideLines(v) |
bool |
Vertical indent guide lines |
setFontSize(s) |
int |
Label font size |
setAccentColor(c) |
Color |
Selection highlight color |
setFlex(n) |
int |
Flex factor in parent |
Keyboard:
↑/↓move selection ·←collapse or jump to parent ·→expand or move to first child ·Home/Endjump to first/last ·Enter/Spacetoggle expand.
Virtualised sortable data grid with resizable columns, alternating rows, scrollbars, and optional reactive data binding.
std::vector<DataColumn> columns = {
DataColumn("name", "Name", 180),
DataColumn("role", "Role", 130),
DataColumn("age", "Age", 60).setAlign(ColumnAlign::Right),
DataColumn("salary", "Salary", 110).setAlign(ColumnAlign::Right)
.setFormatter([](const std::string &v){ return "$" + v + "k"; }),
};
std::vector<DataRow> rows = {
DataRow("1").set("name","Alice").set("role","Engineer").set("age","29").set("salary","120"),
};
auto table = DataTable(columns, rows)
->setAlternateRows(true)
->setOnRowSelected([](int idx, const DataRow &row) {
std::cout << row.get("name") << std::endl;
});
// Reactive rows
State<std::vector<DataRow>> rowsState(..., app);
auto table = DataTable(columns, rowsState);DataColumn
DataColumn col("key", "Label", 120);
col.setAlign(ColumnAlign::Right);
col.setSortable(false);
col.setResizable(false);
col.setMinWidth(40);
col.setFormatter([](const std::string &v){ return "$" + v; });DataRow
DataRow row("optional-id");
row.set("name", "Alice").set("age", "29");
row.get("name");
row.disabled = true;Methods
| Method | Type | Description |
|---|---|---|
setRows(vector<DataRow>) |
— | Replace rows at runtime |
sortBy(key, ascending) |
string, bool |
Sort programmatically |
clearSort() |
— | Remove sort, restore insertion order |
selectedIndex() |
int |
Currently selected visual row index |
selectedRow() |
const DataRow* |
Currently selected row data |
setAlternateRows(v) |
bool |
Alternating row background (default true) |
setShowColumnDividers(v) |
bool |
Vertical column divider lines |
setRowHeight(h) |
int |
Row height in pixels (default 30) |
setHeaderHeight(h) |
int |
Header row height (default 36) |
setHeaderBackground(c) |
Color |
Header background color |
setAccentColor(c) |
Color |
Selection highlight and sort arrow color |
setOnRowSelected(fn) |
void(int, DataRow) |
Fires on single click |
setOnRowDoubleClicked(fn) |
void(int, DataRow) |
Fires on double-click |
setOnSortChanged(fn) |
void(string, bool) |
Fires when sort column changes |
setFlex(n) |
int |
Flex factor in parent |
setWidth(w) / setHeight(h) |
int |
Fixed dimensions |
OpenGL-powered drawing surface embedded in the widget tree.
// Raster canvas — same view and canvas size
auto canvas = RasterCanvas(800, 600);
// With pan/zoom viewport
auto canvas = RasterCanvas(800, 600, 2048, 2048);
canvas->onViewportChanged = [&](float zoom){ updateZoomLabel(zoom); };Factory
| Signature | Description |
|---|---|
Canvas() |
Bare canvas, 400×300, no surface |
Canvas(w, h) |
Bare canvas at given size |
RasterCanvas(w, h) |
Canvas + RasterSurface, viewport disabled |
RasterCanvas(w, h, undoBudget) |
As above with custom undo memory in bytes |
RasterCanvas(viewW, viewH, canvasW, canvasH) |
Canvas + RasterSurface, viewport enabled |
Methods
| Method | Type | Description |
|---|---|---|
setSize(w, h) |
int, int |
View (widget) dimensions |
setCanvasSize(w, h) |
int, int |
Drawing surface dimensions |
setViewportEnabled(bool) |
bool |
Enable/disable pan/zoom |
setScrollbarsEnabled(bool) |
bool |
Show/hide scrollbars |
setSurface<T>(args...) |
Template | Attach a RenderSurface subclass |
getSurface() |
RenderSurface* |
Access active surface |
viewport() |
Viewport& |
Access viewport for zoom/pan control |
redraw() |
— | Schedule a repaint |
onViewportChanged |
function<void(float)> |
Fires when zoom or pan changes |
onGLResize |
function<void(int, int)> |
Fires when GL surface is resized |
GDI+-backed OpenGL raster painting surface with brush engine and undo/redo.
auto surface = canvas->setSurface<RasterSurface>();
surface->setTool(kToolBrush);
StrokeStyle style;
style.r = 0.2f; style.g = 0.4f; style.b = 1.0f;
style.radius = 8.f; style.hardness = 0.9f; style.opacity = 0.8f;
surface->setStrokeStyle(style);
surface->undo();
surface->savePNG(L"output.png");Tool IDs
| Constant | Description |
|---|---|
kToolBrush |
Paints onto scratch FBO, merges on mouse up |
kToolEraser |
Paints white directly onto committed FBO |
Methods
| Method | Type | Description |
|---|---|---|
setTool(id) |
ToolId |
Switch active tool |
setStrokeStyle(style) |
StrokeStyle |
Set color, radius, hardness, opacity |
getStrokeStyle() |
const StrokeStyle& |
Current stroke style |
setOpacity(op) |
float 0–1 |
Stroke opacity shortcut |
undo() / redo() |
— | Undo/redo last stroke |
canUndo() / canRedo() |
bool |
History availability |
clear() |
— | Push undo snapshot then fill white |
savePNG(path) |
wstring |
Export committed layer to PNG |
colorHistory() |
const vector<RGBA>& |
Recently used colors (up to 16) |
Controls zoom and pan. Accessible via canvas->viewport().
auto& vp = canvas->viewport();
vp.zoomIn(); vp.fitToView(); vp.resetZoom();
auto [cx, cy] = vp.screenToCanvas(screenX, screenY);Methods
| Method | Description |
|---|---|
zoomIn() |
Zoom in 1.25× toward view center |
zoomOut() |
Zoom out 0.8× toward view center |
zoomToward(sx, sy, factor) |
Zoom toward a screen-space point |
resetZoom() |
Set zoom = 1 and center canvas |
fitToView() |
Scale and center to fit canvas in viewport |
panByScreen(dx, dy) |
Pan by screen-space pixel deltas |
setOffset(cx, cy) |
Set canvas-space pan offset |
screenToCanvas(sx, sy) |
Convert screen coords to canvas coords |
zoom() |
Current zoom factor |
offsetX() / offsetY() |
Current pan offset |
Ternary-style conditional rendering.
Conditional(isLoggedIn)
->Then([]{ return Dashboard(); })
->Else([]{ return LoginPage(); });
Conditional(itemCount, [](int v){ return v > 0; })
->Then([]{ return ItemList(); })
->Else([]{ return EmptyState(); });| Method | Description |
|---|---|
Then(builder) |
Widget when condition is true |
Else(builder) |
Widget when condition is false |
C++-style switch-case conditional rendering.
Switch(tabIndex)
->Case(0, []{ return HomePage(); })
->Case(1, []{ return ProfilePage(); })
->Default([]{ return ErrorPage(); });| Method | Description |
|---|---|
Case(value, builder) |
Widget when state equals value |
Default(builder) |
Fallback when no case matches |
Lays children out horizontally with flex expansion support.
Row({
Text("Label"),
Expanded(TextInput()),
Button("Send")
})->setSpacing(8)->setCrossAxisAlignment(CrossAxisAlignment::Center);| Method | Type | Description |
|---|---|---|
setSpacing(px) |
int |
Gap between children |
setCrossAxisAlignment(a) |
CrossAxisAlignment |
Vertical alignment |
setMainAxisAlignment(a) |
MainAxisAlignment |
Horizontal distribution |
setMainAxisSize(s) |
MainAxisSize |
Max (fill) or Min (shrink-wrap) |
setWidth(w) |
int |
Fixed width |
setHeight(h) |
int |
Fixed height |
setPadding(p) |
int |
Uniform padding |
setBackgroundColor(c) |
Color |
Row background |
setFlex(n) |
int |
Flex factor in parent |
Lays children out vertically with flex expansion support.
Column({
AppBar("Title"),
Expanded(ListView(itemsState)->itemBuilder(...)),
})->setSpacing(0);| Method | Type | Description |
|---|---|---|
setSpacing(px) |
int |
Gap between children |
setCrossAxisAlignment(a) |
CrossAxisAlignment |
Horizontal alignment |
setMainAxisAlignment(a) |
MainAxisAlignment |
Vertical distribution |
setMainAxisSize(s) |
MainAxisSize |
Max (fill) or Min (shrink-wrap) |
setWidth(w) |
int |
Fixed width |
setHeight(h) |
int |
Fixed height |
setPadding(p) |
int |
Uniform padding |
setBackgroundColor(c) |
Color |
Column background |
setBorderRadius(r) |
int |
Corner rounding |
setMinWidth(w) |
int |
Minimum width |
setFlex(n) |
int |
Flex factor in parent |
Layers children on top of each other. Supports absolute positioning via margins.
Stack(
AssetImage("bg.jpg")->setWidth(400)->setHeight(300),
Positioned(Text("Overlay"), 10, 10)
)->setExpand(true);Factory: Stack(widgets...) or Stack({widget, widget, ...})
Positioned helper
Positioned(child, left, top, right, bottom)
Positioned(child, state, xTransform, yTransform)
Positioned(child, xState, xTransform, yState, yTransform)StackWidget methods
| Method | Description |
|---|---|
setAlignment(a) |
Default alignment for unpositioned children |
setExpand(bool) |
Fill available space instead of shrink-wrapping |
setWidth(w) / setHeight(h) |
Fixed dimensions |
setPadding(p) |
Uniform padding |
setBackgroundColor(c) |
Background fill |
setBorderRadius(r) |
Corner rounding |
setFlex(n) |
Flex factor in parent |
Single-child box with full styling — background, border, radius, padding, margin, size constraints, hover effects.
Container(Text("Hello"))
->setBackgroundColor(RGB(240,248,255))
->setBorderColor(RGB(33,150,243))
->setBorderWidth(1)
->setBorderRadius(8)
->setPadding(16)
->setHoverBackgroundColor(RGB(220,240,255));
// Reactive background
Container(child)->setBackgroundColor(selectedState,
[](bool v){ return v ? RGB(230,245,255) : RGB(255,255,255); });
// Reactive visibility
Container(child)->setVisible(visibleState, [](bool v){ return v; });| Method | Type | Description |
|---|---|---|
setBackgroundColor(color) |
Color |
Fill color |
setBackgroundColor(State, transform) |
State | Reactive background |
setHoverBackgroundColor(color) |
Color |
Fill on hover |
setBorderColor(color) |
Color |
Border stroke |
setBorderColor(State, transform) |
State | Reactive border color |
setHoverBorderColor(color) |
Color |
Border on hover |
setBorderWidth(w) |
int or State |
Border thickness |
setBorderRadius(r) |
int or State |
Corner rounding |
setPadding(p) |
int |
Uniform inner padding |
setPaddingAll(l,t,r,b) |
int ×4 |
Per-side inner padding |
setMargin(m) |
int |
Uniform outer margin |
setMarginAll(l,t,r,b) |
int ×4 |
Per-side outer margin |
setWidth(w) |
int or State |
Fixed width |
setHeight(h) |
int or State |
Fixed height |
setMinWidth(w) |
int |
Minimum width |
setMinHeight(h) |
int |
Minimum height |
setMaxWidth(w) |
int |
Maximum width |
setMaxHeight(h) |
int |
Maximum height |
setFlex(n) |
int |
Flex factor |
setOnHover(fn) |
void(bool) |
Hover enter/leave callback |
setVisible(v) |
bool or State |
Show/hide |
Centers its single child both horizontally and vertically.
Center(Text("No items found")->setTextColor(RGB(150,150,150)));Causes its child to fill remaining space along the parent Row or Column's main axis.
Row({
Text("Label"),
Expanded(TextInput()),
Button("Go")
});
// Proportional — 2:1 split
Row({
Expanded(Column(...), 2),
Expanded(Column(...), 1)
});Factory: Expanded(child, flex = 1)
Methods
| Method | Description |
|---|---|
setFlex(n) |
Override flex factor |
setPadding(p) |
Uniform inner padding |
setBackgroundColor(c) |
Background fill |
Fixed-size box. Used as a spacer or to constrain a child to an exact size.
SizedBox(0, 24); // 24px vertical gap
SizedBox(16, 0); // 16px horizontal gap
SizedBox(200, 48, Button("Submit")); // constrained childUniform padding wrapper. Shorthand for Container with a single padding value.
Padding(16, Text("Padded content"));Two-pane resizable container with a draggable divider.
SplitView(leftWidget, rightWidget, 0.3f)
->setMinPaneWidth(120)
->setDividerColor(RGB(210, 210, 210));
SplitViewVertical(topWidget, bottomWidget, 0.4f);
State<float> ratio(0.5f, app);
SplitView(left, right)->setRatio(ratio);Methods
| Method | Type | Description |
|---|---|---|
setRatio(r) |
float 0–1 |
Fraction of space given to pane 0 |
setRatio(State<float>) |
State | Reactive ratio binding |
setMinPaneWidth(px) |
int |
Minimum size of either pane |
setDividerWidth(px) |
int |
Divider thickness (default 6px) |
setDividerColor(c) |
Color |
Default divider color |
setDividerHoverColor(c) |
Color |
Divider color on hover |
setDividerDragColor(c) |
Color |
Divider color while dragging |
setVertical(v) |
bool |
Switch to top/bottom split |
setResizable(v) |
bool |
Allow drag resize (default true) |
setOnRatioChanged(fn) |
void(float) |
Fires after drag completes |
getRatio() |
float |
Current ratio |
swapPanes() |
— | Swap pane 0 and pane 1 |
collapsePane(idx) |
int |
Collapse pane 0 or 1 fully |
Root structure widget. Manages the overlay stack used by Dropdown, Tooltip, Dialog, and ContextMenu.
Scaffold(
AppBar("My App"),
Column({ Text("Content") })
);Overlay zIndex order: Tooltip = 50, Dropdown = 100, ContextMenu = 150, Dialog = 200.
| Method | Description |
|---|---|
addOverlay(widget, renderer, zIndex) |
Register a floating overlay |
removeOverlay(widget) |
Unregister a floating overlay |
clearOverlays() |
Remove all overlays |
hasOverlays() |
Returns true if overlays are active |
getTopmostOverlay() |
Returns topmost overlay widget pointer |
56px tall header bar with blue background and bold white title.
AppBar("Dashboard");White rounded-corner box with light border and 16px padding.
Card(
Column({
Text("Title")->setFontWeight(FontWeight::Bold),
Text("Description")
})->setSpacing(8)
);Tab bar with swappable content panes.
TabView({
Tab("General", generalWidget),
Tab("Display", displayWidget),
Tab("Network", networkWidget),
})
->setOnTabChanged([](int i) { std::cout << "Tab: " << i << std::endl; });
State<int> activeTab(0, app);
TabView({...})->setActiveIndex(activeTab);Methods
| Method | Type | Description |
|---|---|---|
setActiveIndex(idx) |
int |
Switch to tab by index |
setActiveIndex(State<int>) |
State | Two-way reactive binding |
setOnTabChanged(fn) |
void(int) |
Fires when active tab changes |
setTabBarHeight(h) |
int |
Height of the tab bar (default 40px) |
setTabMinWidth(w) |
int |
Minimum tab button width (default 90px) |
setTabFontSize(s) |
int |
Tab label font size |
setIndicatorColor(c) |
Color |
Active tab underline color |
setActiveTabText(c) |
Color |
Active tab label color |
setBarBackground(c) |
Color |
Tab bar background color |
setContentPadding(p) |
int |
Padding inside the content area |
setHasContentBorder(v) |
bool |
Border around content pane |
setAccentColor(c) |
Color |
Sets indicator, active text, hover together |
setTabContent(idx, widget) |
— | Replace a tab's content at runtime |
setTabLabel(idx, label) |
— | Rename a tab at runtime |
tabCount() |
int |
Number of tabs |
setFlex(n) |
int |
Flex factor in parent |
Horizontal strip of labeled menus with pulldown lists.
auto menuBar = MenuBar({
MenuBarItem("File", {
ContextMenuItem::Action("New", [&]{ newFile(); }),
ContextMenuItem::Separator(),
ContextMenuItem::Action("Exit", []{ PostQuitMessage(0); }),
}),
MenuBarItem("Edit", {
ContextMenuItem::Action("Cut", [&]{ cut(); }),
ContextMenuItem::Action("Copy", [&]{ copy(); }),
}),
});Methods
| Method | Type | Description |
|---|---|---|
setBarHeight(h) |
int |
Height of the menu bar strip (default 28px) |
setBarBackground(c) |
Color |
Bar background color |
setItemHeight(h) |
int |
Dropdown item row height (default 28px) |
setMinMenuWidth(w) |
int |
Minimum dropdown width (default 160px) |
Select input that opens a scrollable overlay list.
Dropdown({"Nepal", "India", "USA", "UK"})
->setPlaceholder("Select a country")
->setSelectedValue(countryState)
->setOnSelectionChanged([&](int i, const std::string& v){
handleSelect(v);
});Factory: Dropdown(options) or Dropdown()
Methods
| Method | Type | Description |
|---|---|---|
setOptions(opts) |
vector<string> |
Set or replace options |
setPlaceholder(text) |
string |
Text when nothing selected |
setSelectedIndex(State<int>) |
State | Two-way binding by index |
setSelectedValue(State<string>) |
State | Two-way binding by value |
setOnSelectionChanged(fn) |
void(int, string) |
Change callback |
setItemHeight(h) |
int |
Row height (default 32px) |
setMaxVisibleItems(n) |
int |
Max rows before scroll (default 6) |
setWidth(w) |
int |
Fixed width |
Floating notification toasts anchored to any point in the tree.
auto toast = Toast()
->setPosition(ToastPosition::BottomRight)
->setMaxVisible(3);
toast->show("File saved", ToastType::Success);
toast->show("Connection lost", ToastType::Error);
toast->showEntry({
.message = "Upload failed",
.title = "Network Error",
.type = ToastType::Error,
.durationMs = 0,
.actionLabel = "Retry",
.onAction = [&]{ retry(); },
});ToastPosition / ToastType — same as before (BottomRight/Left/Center, TopRight/Left/Center; Info/Success/Warning/Error).
Methods
| Method | Type | Description |
|---|---|---|
show(message, type, durationMs) |
— | Quick fire with defaults |
showEntry(ToastEntry) |
— | Full control over all fields |
dismissTop() |
— | Dismiss the topmost visible toast |
dismissAll() |
— | Dismiss all toasts |
setPosition(pos) |
ToastPosition |
Screen corner/edge |
setMaxVisible(n) |
int |
Max simultaneous toasts (default 3) |
setToastWidth(w) |
int |
Toast panel width |
setToastHeight(h) |
int |
Base height per toast |
setMarginEdge(m) |
int |
Distance from window edge |
setSpacing(s) |
int |
Gap between stacked toasts |
setFontSize(s) |
int |
Toast text size |
setBgColor(c) |
Color |
Toast background |
setColors(info, success, warning, error) |
Color ×4 |
Override all accent colors |
Shows a floating text bubble on hover.
Tooltip(
Button("Delete", [&]{ deleteItem(); }),
"Permanently removes the item"
)->setPosition(TooltipPosition::Above);Factory: Tooltip(anchor, text)
Methods
| Method | Type | Description |
|---|---|---|
setTooltipText(text) |
string |
Update tooltip content |
setPosition(pos) |
TooltipPosition |
Above · Below · Auto |
setTooltipBackground(color) |
Color |
Bubble background |
setTooltipTextColor(color) |
Color |
Bubble text color |
setTooltipFontSize(size) |
int |
Font size inside bubble |
setTooltipMaxWidth(w) |
int |
Max bubble width (default 240px) |
Modal overlay with semi-transparent backdrop and centered content panel.
auto dlg = Dialog(
Column({
Text("Confirm delete?")->setFontSize(16),
Row({
Button("Cancel", [&]{ dlg->close(); }),
Button("Delete", [&]{ deleteItem(); dlg->close(); })
})->setSpacing(8)
})
)->setSize(360, 160)
->setCloseOnClickOutside(true);
dlg->open();Methods
| Method | Type | Description |
|---|---|---|
open() |
— | Show the dialog |
close() |
— | Dismiss the dialog |
setContent(widget) |
WidgetPtr |
Set or replace content |
setSize(w, h) |
int, int |
Panel dimensions (default 400×300) |
setCloseOnClickOutside(bool) |
bool |
Close on backdrop click (default true) |
setOverlayAlpha(alpha) |
int 0–255 |
Backdrop opacity (default 128) |
setOnClose(fn) |
void() |
Called when dismissed |
Attaches a right-click context menu to any anchor widget.
ContextMenu(
Text("Right click me"),
{
{"Cut", [&]{ cut(); }},
{"Copy", [&]{ copy(); }},
ContextMenuItem::Separator(),
{"Paste", [&]{ paste(); }, false}
}
);ContextMenuItem
| Factory | Description |
|---|---|
ContextMenuItem(label, action, enabled) |
Action item |
ContextMenuItem::Action(label, action, enabled) |
Explicit action factory |
ContextMenuItem::Separator() |
Visual divider |
Methods
| Method | Type | Description |
|---|---|---|
setMenuItems(items) |
vector<ContextMenuItem> |
Replace all items |
setItemHeight(h) |
int |
Row height (default 28px) |
setMinWidth(w) |
int |
Minimum menu width (default 160px) |
setMenuBackground(color) |
Color |
Menu background |
setMenuBorder(color) |
Color |
Menu border color |
setItemHoverColor(color) |
Color |
Row highlight on hover |
Drop-in audio player widget. Supports local files, HTTP/HTTPS URLs, and in-memory buffers.
// Local file
AudioPlayer("audio/sample.mp3")->setWidth(380);
// Explicit path setter
AudioPlayer()->setPath("audio/sample.mp3")->setWidth(380);
// Stream from URL
AudioPlayerFromUrl("https://example.com/music.mp3")->setWidth(400);
// In-memory buffer
AudioPlayerFromMemory(myBytes)->setWidth(400);
// With artwork
AudioPlayer("audio/track.mp3")
->setArtwork(AssetImage("covers/album.jpg"), 60)
->setWidth(420);Factory
| Signature | Description |
|---|---|
AudioPlayer(path = "") |
Player for a local file path |
AudioPlayerFromUrl(url) |
Player that streams from an HTTP/HTTPS URL |
AudioPlayerFromMemory(bytes) |
Player backed by a vector<uint8_t> buffer |
AudioPlayerFromMemory(ptr, len) |
Player backed by a raw pointer + length |
Methods
| Method | Type | Description |
|---|---|---|
setPath(p) |
string |
Load a local file path |
setUrl(url) |
string |
Stream from HTTP/HTTPS URL (downloaded on background thread) |
setMemory(bytes) |
vector<uint8_t> |
Play from in-memory buffer (copy overload) |
setMemory(ptr, len) |
uint8_t*, size_t |
Play from raw pointer + length |
setArtwork(img, size) |
ImageWidgetPtr, int |
Attach an artwork thumbnail; size defaults to player height |
setArtworkSize(px) |
int |
Resize the artwork column |
setOnDotsClicked(fn) |
void() |
Callback for the three-dot menu button |
setWidth(w) |
int |
Fixed width |
Self-contained video player widget. Blits decoded frames each render tick and overlays a control bar on hover. Supports local files, HTTP/HTTPS URLs, and in-memory buffers.
Platform support: Android (NanoVG/OES), Windows (GDI StretchDIBits), Linux (Cairo/SDL2).
// Local file
VideoPlayer("video/sample.mp4")
->setWidth(480)
->setHeight(270)
->setAutoPlay(true);
// Stream from URL
VideoPlayerFromUrl("https://example.com/video.mp4")
->setWidth(480)->setHeight(270);
// In-memory buffer
VideoPlayerFromMemory(bytes)->setWidth(480)->setHeight(270);Factory
| Signature | Description |
|---|---|
VideoPlayer(path = "") |
Player for a local file path |
VideoPlayerFromUrl(url) |
Player that streams from an HTTP/HTTPS URL |
VideoPlayerFromMemory(bytes) |
Player backed by a vector<uint8_t> buffer |
VideoPlayerFromMemory(ptr, len) |
Player backed by a raw pointer + length |
Methods
| Method | Type | Description |
|---|---|---|
setPath(p) |
string |
Load a local video file |
setUrl(url) |
string |
Stream from HTTP/HTTPS URL |
setMemory(bytes) |
vector<uint8_t> |
Play from in-memory buffer (copy overload) |
setMemory(ptr, len) |
uint8_t*, size_t |
Play from raw pointer + length |
setWidth(w) |
int |
Fixed width |
setHeight(h) |
int |
Fixed height |
setAutoPlay(b) |
bool |
Start playing immediately on open |
Controls: Click anywhere on the video area to toggle play/pause and show the control bar. The bar auto-hides after 3 seconds of inactivity. Drag the seek thumb to scrub.
Fixed-size camera viewfinder with shutter, flash toggle, and camera flip controls.
#include "flux/flux_camera_widget.hpp"
CameraView()
->setWidth(380)
->setHeight(270)
->setOnPhoto([](const std::string& path) {
std::cout << "Saved: " << path << std::endl;
});Methods
| Method | Type | Description |
|---|---|---|
setWidth(w) |
int |
Fixed width (default 380) |
setHeight(h) |
int |
Fixed height (default 270) |
setOnPhoto(fn) |
void(string) |
Fires with the saved file path after each capture |
setStartFront(f) |
bool |
Start with the front-facing camera (Android only) |
Microphone recorder widget with a scrolling live waveform and WAV file output.
#include "flux/mic_recorder_widget.hpp"
MicRecorder()
->setWidth(320)
->setHeight(120)
->setOnSaved([](const std::string& path) {
std::cout << "Saved to: " << path << std::endl;
});Methods
| Method | Type | Description |
|---|---|---|
setWidth(w) |
int |
Fixed width (default 320) |
setHeight(h) |
int |
Fixed height (default 120) |
setOnSaved(fn) |
void(string) |
Fires with the WAV file path on stop |
Flutter-inspired async widget that manages loading, error, and data states for HTTP requests.
#include "flux/flux_future_builder.hpp"
// Raw string response
FetchBuilder(
"https://api.example.com/status",
[](const AsyncSnapshot<std::string>& snap) -> WidgetPtr {
if (snap.isLoading()) return Text("Loading...");
if (snap.hasError()) return Text("Error: " + snap.error);
return Text(snap.data);
}
);
// Parsed JSON
JsonBuilder(
"https://api.example.com/user/1",
[](const AsyncSnapshot<JsonValue>& snap) -> WidgetPtr {
if (snap.isLoading()) return Text("Loading...");
if (snap.hasError()) return Text("Error: " + snap.error);
return Text(snap.data["name"].getString());
}
);
// Typed
TypedJsonBuilder<User>(
"https://api.example.com/user/1",
[](const JsonValue& j) -> User {
return { j["name"].getString(), j["age"].getInt() };
},
[](const AsyncSnapshot<User>& snap) -> WidgetPtr {
if (snap.isLoading()) return Text("Loading...");
if (snap.hasError()) return Text("Error: " + snap.error);
return Text(snap.data.name);
}
);AsyncSnapshot<T>
| Field / Method | Description |
|---|---|
state |
ConnectionState::None · Waiting · Done · Error |
data |
Result value — valid only when hasData() is true |
error |
Error message — valid only when hasError() is true |
isNone() |
True before the fetch starts |
isLoading() |
True while the request is in flight |
hasData() |
True when the request completed successfully |
hasError() |
True when the request failed |
Factory helpers
| Factory | Response type | Description |
|---|---|---|
FetchBuilder(url, builder) |
string |
Raw HTTP response body |
JsonBuilder(url, builder) |
JsonValue |
Parsed JSON value |
TypedJsonBuilder<T>(url, mapper, builder) |
T |
Deserialized struct via a mapper function |
FutureBuilderWidget methods
| Method | Description |
|---|---|
setBuilder(fn) |
Set the builder callback |
setFetcher(fn) |
Set a custom async fetcher instead of HTTP |
refresh() |
Reset state and re-run the fetch |
WebSocket-powered async widget. Opens a persistent connection and calls builder() on every incoming frame so the UI always reflects the latest server push.
#include "flux/flux_stream_builder.hpp"
// Raw text frames
StreamBuilder(
"wss://example.com/feed",
[](const StreamSnapshot<std::string>& snap) -> WidgetPtr {
if (snap.isConnecting()) return Text("Connecting...");
if (snap.hasError()) return Text("Error: " + snap.error);
if (!snap.hasData()) return Text("Waiting for data...");
return Text(snap.data);
}
);
// Auto-parsed JSON
JsonStreamBuilder(
"wss://example.com/prices",
[](const StreamSnapshot<JsonValue>& snap) -> WidgetPtr {
if (snap.isConnecting()) return Text("...");
if (snap.hasError()) return Text("Error: " + snap.error);
if (!snap.hasData()) return Text("–");
return Text(snap.data["price"].getString());
}
);
// Typed — user-supplied mapper
TypedStreamBuilder<TickerData>(
"wss://example.com/ticker",
[](const JsonValue& j) -> TickerData {
return { j["symbol"].getString(), j["price"].getFloat() };
},
[](const StreamSnapshot<TickerData>& snap) -> WidgetPtr {
if (!snap.hasData()) return Text("–");
return Text(snap.data.symbol + ": " + std::to_string(snap.data.price));
}
);StreamSnapshot<T>
| Field / Method | Description |
|---|---|
state |
StreamState::None · Connecting · Active · Done · Error |
data |
Latest decoded value — valid only when hasData() is true |
error |
Error message — valid only when hasError() is true |
isConnecting() |
True during WebSocket handshake |
isActive() |
True while connection is open |
hasData() |
True once at least one frame has been decoded successfully |
isDone() |
True after server closed the connection cleanly |
hasError() |
True on connection failure or server error |
StreamState enum
| Value | Description |
|---|---|
StreamState::None |
Not yet started |
StreamState::Connecting |
Socket handshake in progress |
StreamState::Active |
Connection open, data may have arrived |
StreamState::Done |
Server closed cleanly |
StreamState::Error |
Connection failed or server error |
Factory helpers
| Factory | Frame type | Description |
|---|---|---|
StreamBuilder(url, builder) |
string |
Raw text frames |
JsonStreamBuilder(url, builder) |
JsonValue |
Auto-parsed JSON on every frame |
TypedStreamBuilder<T>(url, mapper, builder) |
T |
Deserialized struct via a mapper function |
StreamBuilderWidget methods
| Method | Description |
|---|---|
setBuilder(fn) |
Set or replace the builder callback |
setDecoder(fn) |
Set a custom frame decoder (string, T&) -> bool |
setUrl(url) |
Set the WebSocket URL |
sendMessage(msg) |
Send a text frame to the server |
reconnect() |
Close and re-open the connection |
snapshot() |
Read the current StreamSnapshot<T> |
The Flux CLI (flux) scaffolds new projects and builds / runs them on each target platform with a single command. Source and releases live at github.com/HeyItsBablu/flux-cli.
| Platform | Requirements |
|---|---|
| All | CMake 3.22+, Git, curl |
| Windows | Visual Studio 2019+ with Desktop development with C++ workload |
| Linux | sudo apt install build-essential cmake git curl |
Linux / macOS
curl -LO https://github.com/HeyItsBablu/flux-cli/releases/latest/download/flux
chmod +x flux
sudo mv flux /usr/local/bin/Windows
- Download
flux.exefrom Releases - Move it to a folder, e.g.
C:\tools\flux\flux.exe - Add that folder to your system
PATH - Open a new terminal and run
fluxto verify
Scaffolds a new app in a folder called <name>.
flux create my_app
cd my_appGenerated structure:
my_app/
├── main.cpp ← your entire app lives here
├── flux.json ← app config (do not edit manually)
├── windows/ ← platform build files (do not edit)
└── linux/ ← platform build files (do not edit)
Builds and launches the app for the given platform.
flux run windows
flux run linux| Platform | What it does |
|---|---|
windows |
Locates Visual Studio, runs CMake + MSVC build, launches build/Release/app.exe |
linux |
Runs CMake + GCC/Clang build, launches build/app |
android |
(coming soon) |
{
"name": "my_app",
"package": "com.example.my_app"
}| Field | Description |
|---|---|
name |
App name used in build output |
package |
Android package identifier |
git clone https://github.com/HeyItsBablu/flux-cli
cd flux-cli
cmake -B build -S .
cmake --build build --config Release





