This library is a wrapper of DearImGui. Dependencies are most easily downloaded via VCPKG, you can use my VCPKG registry to add this library to your project.
In these examples imgui
is an instance of std::unique_ptr<ImGuiInterface>
. Examples only show basic usage, the
classes usually have more functionality.
ImGuiInterface
needs to be subclassed with a custom rendering backend. It must also provide functionality to update
font atlas when requested.
There are some backend implementations in pf_imgui/backends
. If you wish to use those you gotta add them to the
project yourself, they are not part of the library by default.
Most (if not all) elements provide a constructor with a struct as a parameter, which makes it easier to use and makes the code more readable.
Example creation of DragInput<int>
:
window.createChild<DragInput<int>>("drag_int_1", "Drag int", 1.f, 0.f, 100.f);
Example creation of DragInput<int>
with its config:
window.createChild(DragInput<int>::Config{
.name = "drag_int_1",
.label = "Drag int",
.speed = 1.f,
.min = 0.f,
.max = 100.f
});
All the functions which register an observer return an instance of Subscription
which can be used to cancel the
observer.
Many classes allow for changing their style/color via member variables, for example in Button
:
class Button : public ButtonBase, public Labellable, public Resizable {
public:
//...
ColorPalette<ColorOf::Text, ColorOf::TextDisabled, ColorOf::Button, ColorOf::ButtonHovered, ColorOf::ButtonActive,
ColorOf::NavHighlight, ColorOf::Border, ColorOf::BorderShadow>
color;
StyleOptions<StyleOf::FramePadding, StyleOf::FrameRounding, StyleOf::FrameBorderSize, StyleOf::ButtonTextAlign> style;
Font font = Font::Default();
// ...
};
auto &button = window.createChild<Button>("button_id", "Click me");
button.color.set<ColorOf::Button>(Color::Red);
button.style.set<StyleOf::FramePadding>(ImVec2{10, 10});
Many elements provide drag and drop capabilities. For now, elements can only accept a payload of the same type as the source.
auto &sliderSource = imgui->createChild<Slider<float>>(...);
auto &sliderTarget = imgui->createChild<Slider<float>>(...);
sliderSource.setDragAllowed(true);
sliderSource.setDragTooltip("Value: {}"); // if the stored value type is pf::ToStringConvertible, the {} will be replaced with its string representation
sliderTarget.setDropAllowed(true);
Only the default font is created upon ImGuiInterface
creation.
New fonts can be loaded via FontManager
:
auto fontBuilder = imgui->getFontManager().fontBuilder("font name", "path/to/ttf/file");
auto newFont = fontBuilder
.setFontSize(16)
.addSubfont("path/to/ttf/file") // this allows you to add custom fonts which will be baked inside the master one
.setGlyphRange({0xFFFF, 0xFFFF}) // range which will get replaced in the master font
.endSubfont()
.build();
If a font is set to an element it'll be used in its children as well, unless you explicitly set a different font for them.
auto font = imgui->getFontManager().fontByName("arial11");
if (font.has_value()) {
myTextElement.setFont(font);
}
An element which is derived from clickable allows you to add an observer to its click event.
auto &button = window.createChild<Button>("button_id", "Click me");
auto subscription = button.clickEvent.addListener([] {
print("button clicked");
});
// ...
if (something) {
subscription.unsubscribe(); // cancel the observer
}
Elements derived from this interface allow itself to be collapsed. You can also observe this event.
auto &window = imgui->createWindow("window_id", "Window name");
// enables a button to collapse the window, clicking the button makes it collapse and the following callback is called
window.setCollapsible(true);
window.collapsed.addListener([](bool collapsed) {
print("Window collapsed: {}", collapsed);
});
// ...
window.setCollapsed(true);
ItemElement is an element which can receive focus and hover events. It can also have a tooltip and popup menu.
auto &button = window.createChild<Button>("button_id", "Click me");
button.setTooltip("This is a button"); // create a simple text tooltip
button.createTooltip().createChild<Image>(...); // create a tooltip with an image
auto &buttonPopupMenu = button.createOrGetPopupMenu();
buttonPopupMenu.addButonItem("item1", "Remove");
buttonPopupMenu.addButonItem("item2", "Duplicate");
buttonPopupMenu.addCheckboxItem("item3", "Enabled");
button.focused.addListener([] (bool isFocused) {});
button.hovered.addListener([] (bool isHovered) {});
An element which provides some sort of label.
auto &button = window.createChild<Button>("button_id", "THIS IS A LABEL");
button.setLabel("NEW LABEL");
Elements deriving from this interface provide an observable interface for their position. You can also change their position programmatically.
auto &window = imgui->createWindow("window_id", "Window name");
window.position.addListener([](Position newPosition) {});
*window.position.modify() = Position{100, 100};
These elements can have both their width and height controlled. Not many elements can actually provide this capability.
auto &window = imgui->createWindow("window_id", "Window name");
window.size.addListener([] (Size newSize) {});
*window.size.modify() = Size{Width::Auto(), 100};
Elements derived from this interface can be serialized to toml
(and deserialized from it as well). This is used to
save their state to a config file.
auto &checkbox = imgui->createChild<Checkbox>("id", "Checkbox", false, Persistent::Yes);
This decorator can be applied to elements derived from ItemElement
to control their width.
auto &inputText = imgui->createChild<WidthDecorator<InputText>>("id", Width::Auto(), "Text");
inputText.setWidth(100);
auto &window = imgui->createWindow("window_id", "Window name");
// enables a button to close the window, clicking the button makes the window invisible and the following callback is called
window.setCloseable(true);
window.closeEvent.addListener([] {
print("Window closed");
});
// enables a button to collapse the window, clicking the button makes it collapse and the following callback is called
window.setCollapsible(true);
window.collapsed.addListener([](bool collapsed) {
print("Window collapsed: {}", collapsed);
});
// sets size of the window and calls any listeners
*window.size.modify() = Size{100, 50};
// called when setSize is used or size is changed by the user
window.size.addListener([](Size newSize) {
print("Window size: {}x{}", newSize.width, newSize.height);
});
// delimit range of allowed window size
window.setMinSizeConstraints(Size{10, 10});
window.setMaxSizeConstraints(Size{100, 100});
// create an element inside the window
window.createChild<Button>("button_id", "Button label");
// create or get a MenuBar for the window
auto &menuBar = window.createOrGetMenuBar();
A dialog which blocks user from interacting with anything else.
auto &dialog = imgui->getDialogManager().createDialog("dialog_id", "Title");
dialog.createChild<Button>("dialog_close_button", "Close")
.clickEvent.addListener([&dialog]{
dialog.close();
});
// ... add more elements into the dialog
There are some additional ModalDialog
descendants for ease of usage:
InputDialog
for string input.
auto handleInput = [](std::string input) {
print(input);
};
auto handleClose = [] {
print("closed");
};
imgui->getDialogManager().buildInputDialog()
.title("Title")
.message("Message to user")
.onInput(handleInput)
.onCancel(handleClose)
.build();
MessageDialog
to show a message and get user response.
// get the button user clicked and return true if you want to close the dialog
auto handleInput = [](ButtonTypes input) {
if (input == ButtonTypes::Ok) { return true; }
};
imgui->getDialogManager().buildMessageDialog()
.title("Title")
.message("Message to user")
.buttons(MessageButtons::Ok, MessageButtons::Cancel)
.onDone(handleInput)
.build();
FileDialog - uses ImGuiFileDialog
Allows the user to select directories or files with a filter.
const auto onFilesSelected = [](std::vector<std::filesystem::path> selection) {
std::ranges::for_each(selection, printPath);
};
const auto onSelectionCanceled = [] { print("Canceled selection"); };
imgui->getDialogManager().buildFileDialog(FileDialogType::File)
.extension({{"vox", "pf_vox"}, "Voxel model", Color::Red})
.label("Title")
.onSelect(onFilesSelected)
.onCancel(onSelectionCanceled)
.size(Size{500, 400})
.startPath("/home/pf_imgui")
.maxFilesSelected(5)
.modal() // set as modal
.build();
auto &button = window.createChild<Button>("button_id", "Click me");
button.clickEvent.addListener([] {
print("button clicked");
});
A CRTP decorator which adds a bullet to the left of the inner element.
auto &button = window.createChild<Bullet<Button>>("button_id", "Click me");
auto &checkbox = window.createChild<Checkbox>("checkbox_id", "Check me", false);
checkbox.checked.addListener([](bool selected) {
print("Selected: {}", selected);
});
For selection of colors. It supports 3 or 4 component colors and there are two types available:
-
ColorChooserType::Edit
- slider for each component -
ColorChooserType::Picker
- slider for each component and a paletter
TODO: