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::initialize
method.
- You must call the
- Add any Widgets, Buttons, etc. you want to the screen instance, and call the
Screen::setVisible
andScreen::performLayout
methods of yourScreen
instance. - 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::mFont
is not the empty string, this will be used. CallingWidget::setFont
, or by construction (e.g.,Label::Label
’sfont
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, theButton
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 itsWidget::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:
- The
NVGcontext *
associated with aScreen
instance. - 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_map
in the generatedgenerated_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");
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
Theme
string 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.