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.
- 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. - 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.
- You must call the
Screen::initializemethod.
- You must call the
- Add any Widgets, Buttons, etc. you want to the screen instance, and call the
Screen::setVisibleandScreen::performLayoutmethods of yourScreeninstance. - Now that everything is ready, call
nanogui::mainloop(). - 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::mFontis not the empty string, this will be used. CallingWidget::setFont, or by construction (e.g.,Label::Label’sfontparameter), 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::defaultFontis used. For example, theButtonclass 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
Themeinstance via itsWidget::mThemereference. 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->mDefaultFontTheme::GlobalDefaultFonts::NormalBold mTheme->mDefaultBoldFontTheme::GlobalDefaultFonts::BoldMonospace mTheme->mDefaultMonoFontTheme::GlobalDefaultFonts::MonoMonospace Bold mTheme->mDefaultMonoBoldFontTheme::GlobalDefaultFonts::MonoBoldIcons mTheme->mDefaultIconFontTheme::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:
- The
NVGcontext *associated with aScreeninstance. - The name you want to register the font as.
- The “basename” of the font file that was embedded. If you are unsure, search for
__nanogui_font_mapin the generatedgenerated_resources/src/resources.cppin 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");
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:
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
- Override the
Themestring members related to the font faces you want to change the defaults for. - 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.