Usage

C++

There are effectively two ways that you can use NanoGUI in C++: have NanoGUI initialize and manage the OpenGL context (and GLFW), or you do it manually.

  1. If you are letting NanoGUI take over, you must call nanogui::init() before trying to do anything else. If you are managing OpenGL / GLFW yourself, make sure you avoid calling this method.
  2. Create an instance of Screen (or a derived class you have written).
    • NanoGUI managed OpenGL: call the explicit constructor.
    • Self managed OpenGL: call the empty constructor.
  3. Add any Widgets, Buttons, etc. you want to the screen instance, and call the Screen::setVisible and Screen::performLayout methods of your Screen instance.
  4. Now that everything is ready, call nanogui::mainloop().
  5. When all windows are closed, this function will exit, and you should follow it up with a call to nanogui::shutdown().
NanoGUI Managed OpenGL / GLFW:
 Refer to Example 2 for a concise example of what that all looks like.
Self Managed OpenGL / GLFW:
 Refer to Example 3 for an as concise as possible example of what you will need to do to get the Screen to work.

Python

The Python interface is very similar to the C++ API. When you build NanoGUI with CMake, a python folder is created with the library you import nanogui from. Though there are implementation details that differ greatly, the documentation and build process for the Python side is roughly the same. Refer to the Examples and compare the source code for the two.

Example 3 highlights the more notable differences between the APIs. Specifically, that managing GLFW from Python has no meaning, as well as the main loop for Python can easily be detached.

How Fonts are Used

Font Faces

Not every Widget draws text. However, all Widgets have three private member variables that have an associated getter, setter, and default override. Each private member is initialized as the empty string ("").

Widget Private Member Getter Method Setter Method Default Override Method
Widget::mFont Widget::font Widget::setFont Widget::defaultFont
Widget::mTooltipFont Widget::tooltipFont Widget::setTooltipFont Widget::defaultTooltipFont
Widget::mIconFont Widget::iconFont Widget::setIconFont Widget::defaultIconFont

Note

The following documentation will explain mFont, but the mechanics are the same for mTooltipFont and mIconFont.

Warning

Although mIconFont has a default override method available, its usage is generally discouraged. Incorporating an alternative default icon font is better achieved via a custom theme (see Customizing the Default Icon Font) rather than a class-level override.

The idea to keep in mind for font faces in NanoGUI is that it is a hierarchical scheme. These variables are kept private in order to help enforce this hierarchy, as well as prevent usage of Widget::mFont directly (since it more often than not will be the empty string, which is not a valid font face).

Instance Level

If a given widget’s Widget::mFont is not the empty string, this will be used. Calling Widget::setFont, or by construction (e.g., Label::Label’s font parameter), are how to set a font for an individual widget.

In drawing code, the getter will be used:

nvgFontFace(ctx, font().c_str());// ctx is the NanoVG Context

The implementation of Widget::font:

std::string Widger::font() const {
    if (!mFont.empty())
        return mFont;
    return defaultFont();// <- subclasses can override
}
Class Level

If a widget does not have a font face set explicitly, it’s class-level default Widget::defaultFont is used. For example, the Button class defaults to a bold font face. The implementation:

std::string Button::defaultFont() const {
    if (mTheme)
        return mTheme->mDefaultBoldFont;
    return Theme::GlobalDefaultFonts::Bold;
}

Note

The “Class Level” is better thought of as a proxy of sorts to the “Theme Level”, when designing a widget that has a preference to a different font face such as bold or monospace, do not return hard-coded values such as "sans-bold".

Doing so will prevent users of your custom widget from overriding default fonts from their custom theme class.

Theme Level

Every widget being drawn should have access to a Theme instance via its Widget::mTheme reference. In very rare circumstances a Widget may not have a theme reference. These widgets will not be drawn (the only time a widget does not have a theme is when it also does not have a parent). Using the static theme defaults is the preferred fallback, as those font face names will always be valid in NanoGUI.

Font Style Theme Member Variable Static Theme Fallback Variable
Normal mTheme->mDefaultFont Theme::GlobalDefaultFonts::Normal
Bold mTheme->mDefaultBoldFont Theme::GlobalDefaultFonts::Bold
Monospace mTheme->mDefaultMonoFont Theme::GlobalDefaultFonts::Mono
Monospace Bold mTheme->mDefaultMonoBoldFont Theme::GlobalDefaultFonts::MonoBold
Icons mTheme->mDefaultIconFont Theme::GlobalDefaultFonts::Icons

Tip

See Customizing the Default Fonts for all of the possible theme default fonts and what the represent.

Font Sizes

Where font sizes are concerned, a similar form of hierarchical calculation will take place by using the Widget::fontSize method. This function requires a single floating point default font size to fall back on when the widget has not had Widget::mFontSize set (via Widget::setFontSize). For example:

// from src/label.cpp
float fontSize = Widget::fontSize(mTheme->mStandardFontSize);
// from src/button.cpp
float fontSize = Widget::fontSize(mTheme->mButtonFontSize);

The currently available fall-back values are:

How Icons are Used

Icons are specified as integers, and can either be an image or a font icon. Not every widget uses / supports icons, but when it does the functions nvgIsImageIcon and its counterpart nvgIsFontIcon are used to determine how the icon will be rendered. There can be a maximum of 1024 image icons loaded, all other integer values are assumed to be font icons.

The Button is an example of a class that supports icons, either via the constructor or by Button::setIcon.

Image Icons

To load an image icon, use the underlying NanoVG library (#include <nanovg.h>). The function you will likely want to use:

// Creates image by loading it from the disk from specified file name.
// Returns handle to the image.
extern NVG_EXPORT int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags);

// NOTE: imageFlags should be set by using the bit-masking enum values specified
//       by NVGimageFlags also defined in nanovg.h.  At the the time of writing this
//       document, it is defined as:
enum NVGimageFlags {
    NVG_IMAGE_GENERATE_MIPMAPS = 1<<0,// Generate mipmaps during creation of the image.
    NVG_IMAGE_REPEATX          = 1<<1,// Repeat image in X direction.
    NVG_IMAGE_REPEATY          = 1<<2,// Repeat image in Y direction.
    NVG_IMAGE_FLIPY            = 1<<3,// Flips (inverses) image in Y direction when rendered.
    NVG_IMAGE_PREMULTIPLIED    = 1<<4,// Image data has premultiplied alpha.
};

You can obtain the NVGcontext * specific to your instance of Screen via either Screen::nvgContext or Screen::mNVGContext. Assuming the return value is not -1, you can then use the integer return value as the icon for a given widget.

Tip

If all of the images you want to load are in the same directory, you can use the loadImageDirectory function as well.

Font Icons

The default icon font "icons" (see File entypo.h) defines numerous icons available for you to use. If you are embedding custom icon fonts (see Customizing the Default Icon Font) but are not setting this to be the default icon font (via changing Theme::mDefaultIconFont), make sure you call Widget::setIconFont. Otherwise, the default "icons" font will be used, either producing a non-existent or undesired icon to display.

Tip

Using Label? You want to specify the font, rather than the icon font. You can create a label with a font icon by doing something like

new Label(
   parent,
   // nanogui::utf8 accommodates for font icons being in the "private use area"
   std::string(nanogui::utf8(ENTYPO_ICON_CHECK).data()),
   // this sets Widget::mFont, not Widget::mIconFont
   "icons"
);

Customization

The following sections describe how to change the default colors and fonts with NanoGUI. Where custom fonts are concerned, fonts must be loaded for each NanoVG context created, and each Screen has its on NVGcontext. Once a font is loaded, though, it can be used by any child of this Screen instance.

Danger

When overriding font members of the Theme class, you cannot bind new fonts to an existing name. For example, Theme::mDefaultFont starts as "sans". It is not possible to bind a new font face to the name "sans" (this is a limitation of the underlying NanoVG library). For convenience, the following is the list of font names that are already bound, and therefore cannot be re-bound to another font face:

Reserved Name Theme Member that Reserved this Name
"sans" mDefaultFont
"sans-bold" mDefaultBoldFont
"mono" mDefaultMonoFont
"mono-bold" mDefaultMonoBoldFont
"icons" mDefaultIconFont

Note that no errors will occur when you try and bind a new font face to an existing name. It simply won’t occur.

Tip

The NanoGUI Theme Builder can be a useful tool in prototyping color and size modifications to the Theme class.

Loading Custom Fonts

Tip

See the Including Custom Fonts section for how to get custom fonts embedded in NanoGUI.

To load a custom font, you call the nanogui::createFontMem method which is available via #include <nanogui/resources.h>. This resources file is generated from CMake (via bin2c).

The parameters to the function:

  1. The NVGcontext * associated with a Screen instance.
  2. The name you want to register the font as.
  3. The “basename” of the font file that was embedded. If you are unsure, search for __nanogui_font_map in the generated generated_resources/src/resources.cpp in your build directory (find . -name resources.cpp). The basename recorded will be the string key in that map.
auto *screen = new nanogui::Screen(/* ... */);
auto *window = new nanogui::Window(screen, "Window Title");

int fancyFont = nanogui::createFontMem(screen->nvgContext(), "fancy", "fancy.ttf");
// -1 signals error loading the font
if (fancyFont == -1)
    throw std::runtime_error("Could not load 'fancy.ttf'!");

new nanogui::Label(window, "Label Text", "fancy");

Note

Using a derived type of Theme (say CustomTheme) and loading this custom theme in a derived type of Screen is the easiest way to ensure that custom fonts get loaded for the underlying NVGcontext. However, this is not a requirement.

Customizing the Theme Colors and Default Icons

Customizing the default colors and / or icons of Theme is straightforward, simply derive the class and overwrite any values you desire in your derived class constructor:

#include <nanogui/theme.h>
#include <nanogui/entypo.h> // the default icons font

class CustomTheme : public nanogui::Theme {
public:
    CustomTheme(NVGcontext *ctx) : nanogui::Theme(ctx) {
        using nanogui::Color;
        // ... change any colors you want ...
        mBorderDark = Color(111, 255);
        // ... change any default icons you want ...
        // default: ``ENTYPO_ICON_CHECK``
        mCheckBoxIcon = ENTYPO_ICON_CROSS;
        mCheckBoxIconExtraScale = 1.3f;
    }
};

All of the member variables in Theme are public, so you can also modify them directly (obtain the theme from Widget::theme).

Where default icons for widgets are concerned (the above example shows how to change CheckBox), there is an associated floating point scale factor for the icon. This is because the codepoint of the icons in the default Entypo+ icon font are not all perfectly compatible. When changing the default icons, you will likely want to also adjust the default icon scaling.

Note

At this time, there are three widgets that have custom icon scaling:

  1. CheckBox (via Theme::mCheckBoxIconExtraScale).
  2. PopupButton (via Theme::mPopupIconExtraScale).
  3. TextBox (via Theme::mTextBoxIconExtraScale).

Customizing the Default Fonts

Tip

See the Including Custom Fonts section for how to get custom fonts embedded in NanoGUI.

Assuming you want to use a custom font face, you need to load the font yourself. When NanoGUI builds, it uses bin2c to generate nanogui/resources.h and the associated implementation file. Assuming you requested customfont.ttf and customfont-bold.ttf via NANOGUI_EXTRA_RESOURCES, then you want to

  1. Override the Theme string members related to the font faces you want to change the defaults for.
  2. Load the fonts using nanogui::createFontMem (see Loading Custom Fonts for more information on the parameters to this method).
#include <nanogui/theme.h>
#include <nanogui/resources.h> // provides nanogui::createFontMem

class CustomTheme : public nanogui::Theme {
public:
    CustomTheme(NVGcontext *ctx) : nanogui::Theme(ctx) {
        // Step 1: override the nanogui::Theme font members you seek to change
        mDefaultFont     = "custom";
        mDefaultBoldFont = "custom-bold";
        // Step 2: load the custom fonts.
        mCustomFont     = nanogui::createFontMem(ctx, mDefaultFont.c_str(), "customfont.ttf");
        mCustomFontBold = nanogui::createFontMem(ctx, mDefaultBoldFont.c_str(), "customfont-bold.ttf");
        // -1 means error loading font
        if (mCustomFont == -1 || mCustomFontBold == -1)
            throw std::runtime_error("Could not load customfont!");
    }

protected:
    int mCustomFont = -1;
    int mCustomFontBold = -1;
};

Note

Changing these sets the default fonts globally. To change the font face for one specific widget, call Widget::setFont.

Customizing the Default Icon Font

Tip

See the Including Custom Icon Fonts section for how to get custom icon fonts embedded in NanoGUI.

Warning

The default icon font "icons" (see File entypo.h) has all characters defined in the private use area range. This is not a hard requirement, but the values must be greater than 1024 in order for nvgIsImageIcon and nvgIsFontIcon to behave appropriately.

See How Icons are Used for more information.

The process for custom icon fonts is nearly the same: override a Theme member, and load the font. However, now that you have changed the icon font, you must override all theme variables related to actual icon codes (since you are using a different font now). Assuming you embedded customicons.ttf with NANOGUI_EXTRA_ICON_RESOURCES (meaning there was a corresponding customicons.h C++ header file defining the newly available icons):

#include <nanogui/theme.h>
#include <nanogui/resources.h>   // provides nanogui::createFontMem
#include <nanogui/customicons.h> // copied to nanogui/customicons.h for you

class CustomTheme : public nanogui::Theme {
public:
    CustomTheme(NVGcontext *ctx) : nanogui::Theme(ctx) {
        // Step 1: override the nanogui::Theme font member related to icons
        mDefaultIconFont = "customicons";
        // Step 2: load the customicons font
        mCustomIconsFont = nanogui::createFontMem(ctx, mDefaultIconFont.c_str(), "customicons.ttf");
        // -1 means error loading font
        if (mCustomIconsFont == -1)
            throw std::runtime_error("Could not load customicons font!");

        // Step 3: overwrite *ALL* icon variables
        // mCheckBoxIcon = CUSTOMICONS_ICON_SOMETHING;
        // mCheckBoxIconExtraScale = ???;
    };

protected:
    int mCustomIconsFont = -1;
};

Note

Changing this sets the default fonts globally. To change the icon font face for one specific widget, call Widget::setIconFont.

Using Custom Themes

Now that we have some derived CustomTheme class, we want to use it. First, let us understand how Theme is used.

auto *screen = new nanogui::Screen(/* ... */);
auto *window = new nanogui::Window(window, "Window Title");
window->setLayout(new nanogui::GroupLayout());
new nanogui::Label(window, "label text");

When Screen is initialized (Screen::initialize), the Theme is created. Every Widget (for which Screen is a derived type of) contains a reference to a Themme instance in nanogui::Widget::mTheme. So when window and the label are created above, the same Theme instance now has three separate widgets that refer to it.

To apply a custom theme globally:

auto *screen = new nanogui::Screen(/* ... */);
nanogui::ref<CustomTheme> theme = new CustomTheme(screen->nvgContext());
screen->setTheme(theme);
auto *window = new nanogui::Window(window, "Window Title");
// add remaining widgets

Since the Theme is always inherited from the parent, all newly created children of screen will contain a reference to the CustomTheme instance.

Note

Nothing requires that you set the theme globally on a Screen instance. You can apply the theme to one specific Window, for example.

Note

When Widget::setTheme is called, the call is propagated to all children. So you can just as easily create all of the widgets first, and call setTheme on the desired parent.

Tip

See Loading Custom Fonts for more information on the nanogui::createFontMem method.