Dario Manesku 11 лет назад
Родитель
Сommit
101c2c3ba0

+ 1305 - 0
examples/20-nanovg/blendish.h

@@ -0,0 +1,1305 @@
+/*
+Blendish - Blender 2.5 UI based theming functions for NanoVG
+
+Copyright (c) 2014 Leonard Ritter <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef BLENDISH_H
+#define BLENDISH_H
+
+#ifndef NANOVG_H
+#error "nanovg.h must be included first."
+#endif
+
+#define fmaxf bx::fmax
+#define fminf bx::fmin
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+
+Revision 3 (2014-07-08)
+
+Summary
+-------
+
+Blendish is a small collection of drawing functions for NanoVG, designed to
+replicate the look of the Blender 2.5+ User Interface. You can use these
+functions to theme your UI library. Several metric constants for faithful
+reproduction are also included.
+
+Blendish supports the original Blender icon sheet; As the licensing of Blenders
+icons is unclear, they are not included in Blendishes repository, but a SVG
+template, "icons_template.svg" is provided, which you can use to build your own
+icon sheet.
+
+To use icons, you must first load the icon sheet using one of the
+nvgCreateImage*() functions and then pass the image handle to bndSetIconImage();
+otherwise, no icons will be drawn. See bndSetIconImage() for more information.
+
+Blendish will not render text until a suitable UI font has been passed to
+bndSetFont() has been called. See bndSetFont() for more information.
+
+
+Drawbacks
+---------
+
+There is no support varying dpi resolutions yet. The library is hardcoded
+to the equivalent of 72 dpi in the Blender system settings.
+
+Support for label truncation is missing. Text rendering breaks when widgets are
+too short to contain their labels.
+
+Usage
+-----
+
+To use this header file in implementation mode, define BLENDISH_IMPLEMENTATION
+before including blendish.h, otherwise the file will be in header-only mode.
+
+*/
+
+// if that typedef is provided elsewhere, you may define
+// BLENDISH_NO_NVG_TYPEDEFS before including the header.
+#ifndef BLENDISH_NO_NVG_TYPEDEFS
+typedef struct NVGcontext NVGcontext;
+typedef struct NVGcolor NVGcolor;
+typedef struct NVGglyphPosition NVGglyphPosition;
+#endif
+
+// describes the theme used to draw a single widget or widget box;
+// these values correspond to the same values that can be retrieved from
+// the Theme panel in the Blender preferences
+typedef struct BNDwidgetTheme {
+    // color of widget box outline
+    NVGcolor outlineColor;
+    // color of widget item (meaning changes depending on class)
+    NVGcolor itemColor;
+    // fill color of widget box
+    NVGcolor innerColor;
+    // fill color of widget box when active
+    NVGcolor innerSelectedColor;
+    // color of text label
+    NVGcolor textColor;
+    // color of text label when active
+    NVGcolor textSelectedColor;
+    // delta modifier for upper part of gradient (-100 to 100)
+    int shadeTop;
+    // delta modifier for lower part of gradient (-100 to 100)
+    int shadeDown;
+} BNDwidgetTheme;
+
+// describes the theme used to draw widgets
+typedef struct BNDtheme {
+    // the background color of panels and windows
+    NVGcolor backgroundColor;
+    // theme for labels
+    BNDwidgetTheme regularTheme;
+    // theme for tool buttons
+    BNDwidgetTheme toolTheme;
+    // theme for radio buttons
+    BNDwidgetTheme radioTheme;
+    // theme for text fields
+    BNDwidgetTheme textFieldTheme;
+    // theme for option buttons (checkboxes)
+    BNDwidgetTheme optionTheme;
+    // theme for choice buttons (comboboxes)
+    // Blender calls them "menu buttons"
+    BNDwidgetTheme choiceTheme;
+    // theme for number fields
+    BNDwidgetTheme numberFieldTheme;
+    // theme for slider controls
+    BNDwidgetTheme sliderTheme;
+    // theme for scrollbars
+    BNDwidgetTheme scrollBarTheme;
+    // theme for tooltips
+    BNDwidgetTheme tooltipTheme;
+    // theme for menu backgrounds
+    BNDwidgetTheme menuTheme;
+    // theme for menu items
+    BNDwidgetTheme menuItemTheme;
+} BNDtheme;
+
+// how text on a control is aligned
+typedef enum BNDtextAlignment {
+    BND_LEFT = 0,
+    BND_CENTER,
+} BNDtextAlignment;
+
+// states altering the styling of a widget
+typedef enum BNDwidgetState {
+    // not interacting
+    BND_DEFAULT = 0,
+    // the mouse is hovering over the control
+    BND_HOVER,
+    // the widget is activated (pressed) or in an active state (toggled)
+    BND_ACTIVE
+} BNDwidgetState;
+
+// flags indicating which corners are sharp (for grouping widgets)
+typedef enum BNDcornerFlags {
+    // all corners are round
+    BND_CORNER_NONE = 0,
+    // sharp top left corner
+    BND_CORNER_TOP_LEFT = 1,
+    // sharp top right corner
+    BND_CORNER_TOP_RIGHT = 2,
+    // sharp bottom right corner
+    BND_CORNER_DOWN_RIGHT = 4,
+    // sharp bottom left corner
+    BND_CORNER_DOWN_LEFT = 8,
+    // all corners are sharp;
+    // you can invert a set of flags using ^= BND_CORNER_ALL
+    BND_CORNER_ALL = 0xF,
+    // top border is sharp
+    BND_CORNER_TOP = 3,
+    // bottom border is sharp
+    BND_CORNER_DOWN = 0xC,
+    // left border is sharp
+    BND_CORNER_LEFT = 9,
+    // right border is sharp
+    BND_CORNER_RIGHT = 6
+} BNDcornerFlags;
+
+// build an icon ID from two coordinates into the icon sheet, where
+// (0,0) designates the upper-leftmost icon, (1,0) the one right next to it,
+// and so on.
+#define BND_ICONID(x,y) ((x)|((y)<<8))
+
+// default widget height
+#define BND_WIDGET_HEIGHT 21
+// default toolbutton width (if icon only)
+#define BND_TOOL_WIDTH 20
+
+// width of vertical scrollbar
+#define BND_SCROLLBAR_WIDTH 13
+// height of horizontal scrollbar
+#define BND_SCROLLBAR_HEIGHT 14
+
+////////////////////////////////////////////////////////////////////////////////
+
+// set the current theme all widgets will be drawn with.
+// the default Blender 2.6 theme is set by default.
+void bndSetTheme(BNDtheme theme);
+
+// Returns the currently set theme
+const BNDtheme *bndGetTheme();
+
+// designates an image handle as returned by nvgCreateImage*() as the themes'
+// icon sheet. The icon sheet format must be compatible to Blender 2.6's icon
+// sheet; the order of icons does not matter.
+// A valid icon sheet is e.g. shown at
+// http://wiki.blender.org/index.php/Dev:2.5/Doc/How_to/Add_an_icon
+void bndSetIconImage(int image);
+
+// designates an image handle as returned by nvgCreateFont*() as the themes'
+// UI font. Blender's original UI font Droid Sans is perfectly suited and
+// available here:
+// https://svn.blender.org/svnroot/bf-blender/trunk/blender/release/datafiles/fonts/
+void bndSetFont(int font);
+
+////////////////////////////////////////////////////////////////////////////////
+
+// High Level Functions
+// --------------------
+// Use these functions to draw themed widgets with your NVGcontext.
+
+// Draw a label with its lower left origin at (x,y) and size of (w,h).
+// if iconid >= 0, an icon will be added to the widget
+// if label is not NULL, a label will be added to the widget
+// widget looks best when height is BND_WIDGET_HEIGHT
+void bndLabel(NVGcontext *ctx,
+    float x, float y, float w, float h, int iconid, const char *label);
+
+// Draw a tool button  with its lower left origin at (x,y) and size of (w,h),
+// where flags is one or multiple flags from BNDcornerFlags and state denotes
+// the widgets current UI state.
+// if iconid >= 0, an icon will be added to the widget
+// if label is not NULL, a label will be added to the widget
+// widget looks best when height is BND_WIDGET_HEIGHT
+void bndToolButton(NVGcontext *ctx,
+    float x, float y, float w, float h, int flags, BNDwidgetState state,
+    int iconid, const char *label);
+
+// Draw a radio button with its lower left origin at (x,y) and size of (w,h),
+// where flags is one or multiple flags from BNDcornerFlags and state denotes
+// the widgets current UI state.
+// if iconid >= 0, an icon will be added to the widget
+// if label is not NULL, a label will be added to the widget
+// widget looks best when height is BND_WIDGET_HEIGHT
+void bndRadioButton(NVGcontext *ctx,
+    float x, float y, float w, float h, int flags, BNDwidgetState state,
+    int iconid, const char *label);
+
+// Draw a text field with its lower left origin at (x,y) and size of (w,h),
+// where flags is one or multiple flags from BNDcornerFlags and state denotes
+// the widgets current UI state.
+// if iconid >= 0, an icon will be added to the widget
+// if text is not NULL, text will be printed to the widget
+// cbegin must be >= 0 and <= strlen(text) and denotes the beginning of the caret
+// cend must be >= cbegin and <= strlen(text) and denotes the end of the caret
+// if cend < cbegin, then no caret will be drawn
+// widget looks best when height is BND_WIDGET_HEIGHT
+void bndTextField(NVGcontext *ctx,
+    float x, float y, float w, float h, int flags, BNDwidgetState state,
+    int iconid, const char *text, int cbegin, int cend);
+
+// Draw an option button with its lower left origin at (x,y) and size of (w,h),
+// where flags is one or multiple flags from BNDcornerFlags and state denotes
+// the widgets current UI state.
+// if label is not NULL, a label will be added to the widget
+// widget looks best when height is BND_WIDGET_HEIGHT
+void bndOptionButton(NVGcontext *ctx,
+    float x, float y, float w, float h, BNDwidgetState state,
+    const char *label);
+
+// Draw a choice button with its lower left origin at (x,y) and size of (w,h),
+// where flags is one or multiple flags from BNDcornerFlags and state denotes
+// the widgets current UI state.
+// if iconid >= 0, an icon will be added to the widget
+// if label is not NULL, a label will be added to the widget
+// widget looks best when height is BND_WIDGET_HEIGHT
+void bndChoiceButton(NVGcontext *ctx,
+    float x, float y, float w, float h, int flags, BNDwidgetState state,
+    int iconid, const char *label);
+
+// Draw a number field with its lower left origin at (x,y) and size of (w,h),
+// where flags is one or multiple flags from BNDcornerFlags and state denotes
+// the widgets current UI state.
+// if label is not NULL, a label will be added to the widget
+// if value is not NULL, a value will be added to the widget, along with
+// a ":" separator
+// widget looks best when height is BND_WIDGET_HEIGHT
+void bndNumberField(NVGcontext *ctx,
+    float x, float y, float w, float h, int flags, BNDwidgetState state,
+    const char *label, const char *value);
+
+// Draw slider control with its lower left origin at (x,y) and size of (w,h),
+// where flags is one or multiple flags from BNDcornerFlags and state denotes
+// the widgets current UI state.
+// progress must be in the range 0..1 and controls the size of the slider bar
+// if label is not NULL, a label will be added to the widget
+// if value is not NULL, a value will be added to the widget, along with
+// a ":" separator
+// widget looks best when height is BND_WIDGET_HEIGHT
+void bndSlider(NVGcontext *ctx,
+    float x, float y, float w, float h, int flags, BNDwidgetState state,
+    float progress, const char *label, const char *value);
+
+// Draw scrollbar with its lower left origin at (x,y) and size of (w,h),
+// where state denotes the widgets current UI state.
+// offset is in the range 0..1 and controls the position of the scroll handle
+// size is in the range 0..1 and controls the size of the scroll handle
+// horizontal widget looks best when height is BND_SCROLLBAR_HEIGHT,
+// vertical looks best when width is BND_SCROLLBAR_WIDTH
+void bndScrollBar(NVGcontext *ctx,
+    float x, float y, float w, float h, BNDwidgetState state,
+    float offset, float size);
+
+// Draw a menu background with its lower left origin at (x,y) and size of (w,h),
+// where flags is one or multiple flags from BNDcornerFlags.
+void bndMenuBackground(NVGcontext *ctx,
+    float x, float y, float w, float h, int flags);
+
+// Draw a menu label with its lower left origin at (x,y) and size of (w,h).
+// if iconid >= 0, an icon will be added to the widget
+// if label is not NULL, a label will be added to the widget
+// widget looks best when height is BND_WIDGET_HEIGHT
+void bndMenuLabel(NVGcontext *ctx,
+    float x, float y, float w, float h, int iconid, const char *label);
+
+// Draw a menu item with its lower left origin at (x,y) and size of (w,h),
+// where state denotes the widgets current UI state.
+// if iconid >= 0, an icon will be added to the widget
+// if label is not NULL, a label will be added to the widget
+// widget looks best when height is BND_WIDGET_HEIGHT
+void bndMenuItem(NVGcontext *ctx,
+    float x, float y, float w, float h, BNDwidgetState state,
+    int iconid, const char *label);
+
+// Draw a tooltip background with its lower left origin at (x,y) and size of (w,h)
+void bndTooltipBackground(NVGcontext *ctx, float x, float y, float w, float h);
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Low Level Functions
+// -------------------
+// these are part of the implementation detail and can be used to theme
+// new kinds of controls in a similar fashion.
+
+// make color transparent using the default alpha value
+NVGcolor bndTransparent(NVGcolor color);
+
+// offset a color by a given integer delta in the range -100 to 100
+NVGcolor bndOffsetColor(NVGcolor color, int delta);
+
+// assigns radius r to the four entries of array radiuses depending on whether
+// the corner is marked as sharp or not; see BNDcornerFlags for possible
+// flag values.
+void bndSelectCorners(float *radiuses, float r, int flags);
+
+// computes the upper and lower gradient colors for the inner box from a widget
+// theme and the widgets state. If flipActive is set and the state is
+// BND_ACTIVE, the upper and lower colors will be swapped.
+void bndInnerColors(NVGcolor *shade_top, NVGcolor *shade_down,
+    const BNDwidgetTheme *theme, BNDwidgetState state, int flipActive);
+
+// computes the text color for a widget label from a widget theme and the
+// widgets state.
+NVGcolor bndTextColor(const BNDwidgetTheme *theme, BNDwidgetState state);
+
+// computes the bounds of the scrollbar handle from the scrollbar size
+// and the handles offset and size.
+// offset is in the range 0..1 and defines the position of the scroll handle
+// size is in the range 0..1 and defines the size of the scroll handle
+void bndScrollHandleRect(float *x, float *y, float *w, float *h,
+    float offset, float size);
+
+// Add a rounded box path at position (x,y) with size (w,h) and a separate
+// radius for each corner listed in clockwise order, so that cr0 = top left,
+// cr1 = top right, cr2 = bottom right, cr3 = bottom left;
+// this is a low level drawing function: the path must be stroked or filled
+// to become visible.
+void bndRoundedBox(NVGcontext *ctx, float x, float y, float w, float h,
+    float cr0, float cr1, float cr2, float cr3);
+
+// Draw a flat panel without any decorations at position (x,y) with size (w,h)
+// and fills it with backgroundColor
+void bndBackground(NVGcontext *ctx, float x, float y, float w, float h);
+
+// Draw a lower inset for a rounded box at position (x,y) with size (w,h)
+// that gives the impression the surface has been pushed in.
+// cr2 and cr3 contain the radiuses of the bottom right and bottom left
+// corners of the rounded box.
+void bndBevelInset(NVGcontext *ctx, float x, float y, float w, float h,
+    float cr2, float cr3);
+
+// Draw an icon with (x,y) as its upper left coordinate; the iconid selects
+// the icon from the sheet; use the BND_ICONID macro to build icon IDs.
+void bndIcon(NVGcontext *ctx, float x, float y, int iconid);
+
+// Draw a drop shadow around the rounded box at (x,y) with size (w,h) and
+// radius r, with feather as its maximum range in pixels.
+// No shadow will be painted inside the rounded box.
+void bndDropShadow(NVGcontext *ctx, float x, float y, float w, float h,
+    float r, float feather, float alpha);
+
+// Draw the inner part of a widget box, with a gradient from shade_top to
+// shade_down. If h>w, the gradient will be horizontal instead of
+// vertical.
+void bndInnerBox(NVGcontext *ctx, float x, float y, float w, float h,
+    float cr0, float cr1, float cr2, float cr3,
+    NVGcolor shade_top, NVGcolor shade_down);
+
+// Draw the outline part of a widget box with the given color
+void bndOutlineBox(NVGcontext *ctx, float x, float y, float w, float h,
+    float cr0, float cr1, float cr2, float cr3, NVGcolor color);
+
+// Draw an optional icon specified by <iconid> and an optional label with
+// given alignment (BNDtextAlignment), fontsize and color within a widget box.
+// if iconid is >= 0, an icon will be drawn and the labels remaining space
+// will be adjusted.
+// if label is not NULL, it will be drawn with the specified alignment, fontsize
+// and color.
+// if value is not NULL, label and value will be drawn with a ":" separator
+// inbetween.
+void bndIconLabelValue(NVGcontext *ctx, float x, float y, float w, float h,
+    int iconid, NVGcolor color, int align, float fontsize, const char *label,
+    const char *value);
+
+// Draw an optional icon specified by <iconid>, an optional label and
+// a caret with given fontsize and color within a widget box.
+// if iconid is >= 0, an icon will be drawn and the labels remaining space
+// will be adjusted.
+// if label is not NULL, it will be drawn with the specified alignment, fontsize
+// and color.
+// cbegin must be >= 0 and <= strlen(text) and denotes the beginning of the caret
+// cend must be >= cbegin and <= strlen(text) and denotes the end of the caret
+// if cend < cbegin, then no caret will be drawn
+void bndIconLabelCaret(NVGcontext *ctx, float x, float y, float w, float h,
+    int iconid, NVGcolor color, float fontsize, const char *label,
+    NVGcolor caretcolor, int cbegin, int cend);
+
+// Draw a checkmark for an option box with the given upper left coordinates
+// (ox,oy) with the specified color.
+void bndCheck(NVGcontext *ctx, float ox, float oy, NVGcolor color);
+
+// Draw a horizontal arrow for a number field with its center at (x,y) and
+// size s; if s is negative, the arrow points to the left.
+void bndArrow(NVGcontext *ctx, float x, float y, float s, NVGcolor color);
+
+// Draw an up/down arrow for a choice box with its center at (x,y) and size s
+void bndUpDownArrow(NVGcontext *ctx, float x, float y, float s, NVGcolor color);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // BLENDISH_H
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef BLENDISH_IMPLEMENTATION
+
+#include <memory.h>
+#include <math.h>
+
+#ifdef _MSC_VER
+	#pragma warning (disable: 4996) // Switch off security warnings
+	#pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings
+	#ifdef __cplusplus
+	#define BND_INLINE inline
+	#else
+	#define BND_INLINE
+	#endif
+#else
+	#define BND_INLINE inline
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+// default text size
+#define BND_LABEL_FONT_SIZE 13
+
+// default text padding in inner box
+#define BND_PAD_LEFT 8
+#define BND_PAD_RIGHT 8
+
+// label: value separator string
+#define BND_LABEL_SEPARATOR ": "
+
+// alpha intensity of transparent items (0xa4)
+#define BND_TRANSPARENT_ALPHA 0.643
+
+// shade intensity of beveled insets
+#define BND_BEVEL_SHADE 30
+// shade intensity of hovered inner boxes
+#define BND_HOVER_SHADE 30
+
+// width of icon sheet
+#define BND_ICON_SHEET_WIDTH 602
+// height of icon sheet
+#define BND_ICON_SHEET_HEIGHT 640
+// gridsize of icon sheet in both dimensions
+#define BND_ICON_SHEET_GRID 21
+// offset of first icon tile relative to left border
+#define BND_ICON_SHEET_OFFSET_X 5
+// offset of first icon tile relative to top border
+#define BND_ICON_SHEET_OFFSET_Y 10
+// resolution of single icon
+#define BND_ICON_SHEET_RES 16
+
+// size of number field arrow
+#define BND_NUMBER_ARROW_SIZE 4
+
+// default text color
+#define BND_COLOR_TEXT {{{ 0,0,0,1 }}}
+// default highlighted text color
+#define BND_COLOR_TEXT_SELECTED {{{ 1,1,1,1 }}}
+
+// radius of tool button
+#define BND_TOOL_RADIUS 4
+
+// radius of option button
+#define BND_OPTION_RADIUS 4
+// width of option button checkbox
+#define BND_OPTION_WIDTH 14
+// height of option button checkbox
+#define BND_OPTION_HEIGHT 15
+
+// radius of text field
+#define BND_TEXT_RADIUS 4
+
+// radius of number button
+#define BND_NUMBER_RADIUS 10
+
+// radius of menu popup
+#define BND_MENU_RADIUS 3
+// feather of menu popup shadow
+#define BND_SHADOW_FEATHER 12
+// alpha of menu popup shadow
+#define BND_SHADOW_ALPHA 0.5
+
+// radius of scrollbar
+#define BND_SCROLLBAR_RADIUS 7
+// shade intensity of active scrollbar
+#define BND_SCROLLBAR_ACTIVE_SHADE 15
+
+// max glyphs for position testing
+#define BND_MAX_GLYPHS 1024
+
+////////////////////////////////////////////////////////////////////////////////
+
+BND_INLINE float bnd_clamp(float v, float mn, float mx) {
+    return (v > mx)?mx:(v < mn)?mn:v;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// the initial theme
+static BNDtheme bnd_theme = {
+    // backgroundColor
+    {{{ 0.447, 0.447, 0.447, 1.0 }}},
+    // regularTheme
+    {
+        {{{ 0.098,0.098,0.098,1 }}}, // color_outline
+        {{{ 0.098,0.098,0.098,1 }}}, // color_item
+        {{{ 0.6,0.6,0.6,1 }}}, // color_inner
+        {{{ 0.392,0.392,0.392,1 }}}, // color_inner_selected
+        BND_COLOR_TEXT, // color_text
+        BND_COLOR_TEXT_SELECTED, // color_text_selected
+        0, // shade_top
+        0, // shade_down
+    },
+    // toolTheme
+    {
+        {{{ 0.098,0.098,0.098,1 }}}, // color_outline
+        {{{ 0.098,0.098,0.098,1 }}}, // color_item
+        {{{ 0.6,0.6,0.6,1 }}}, // color_inner
+        {{{ 0.392,0.392,0.392,1 }}}, // color_inner_selected
+        BND_COLOR_TEXT, // color_text
+        BND_COLOR_TEXT_SELECTED, // color_text_selected
+        15, // shade_top
+        -15, // shade_down
+    },
+    // radioTheme
+    {
+        {{{ 0,0,0,1 }}}, // color_outline
+        {{{ 1,1,1,1 }}}, // color_item
+        {{{ 0.275,0.275,0.275,1 }}}, // color_inner
+        {{{ 0.337,0.502,0.761,1 }}}, // color_inner_selected
+        BND_COLOR_TEXT_SELECTED, // color_text
+        BND_COLOR_TEXT, // color_text_selected
+        15, // shade_top
+        -15, // shade_down
+    },
+    // textFieldTheme
+    {
+        {{{ 0.098,0.098,0.098,1 }}}, // color_outline
+        {{{ 0.353, 0.353, 0.353,1 }}}, // color_item
+        {{{ 0.6, 0.6, 0.6,1 }}}, // color_inner
+        {{{ 0.6, 0.6, 0.6,1 }}}, // color_inner_selected
+        BND_COLOR_TEXT, // color_text
+        BND_COLOR_TEXT_SELECTED, // color_text_selected
+        0, // shade_top
+        25, // shade_down
+    },
+    // optionTheme
+    {
+        {{{ 0,0,0,1 }}}, // color_outline
+        {{{ 1,1,1,1 }}}, // color_item
+        {{{ 0.275,0.275,0.275,1 }}}, // color_inner
+        {{{ 0.275,0.275,0.275,1 }}}, // color_inner_selected
+        BND_COLOR_TEXT, // color_text
+        BND_COLOR_TEXT_SELECTED, // color_text_selected
+        15, // shade_top
+        -15, // shade_down
+    },
+    // choiceTheme
+    {
+        {{{ 0,0,0,1 }}}, // color_outline
+        {{{ 1,1,1,1 }}}, // color_item
+        {{{ 0.275,0.275,0.275,1 }}}, // color_inner
+        {{{ 0.275,0.275,0.275,1 }}}, // color_inner_selected
+        BND_COLOR_TEXT_SELECTED, // color_text
+        {{{ 0.8,0.8,0.8,1 }}}, // color_text_selected
+        15, // shade_top
+        -15, // shade_down
+    },
+    // numberFieldTheme
+    {
+        {{{ 0.098,0.098,0.098,1 }}}, // color_outline
+        {{{ 0.353, 0.353, 0.353,1 }}}, // color_item
+        {{{ 0.706, 0.706, 0.706,1 }}}, // color_inner
+        {{{ 0.6, 0.6, 0.6,1 }}}, // color_inner_selected
+        BND_COLOR_TEXT, // color_text
+        BND_COLOR_TEXT_SELECTED, // color_text_selected
+        -20, // shade_top
+        0, // shade_down
+    },
+    // sliderTheme
+    {
+        {{{ 0.098,0.098,0.098,1 }}}, // color_outline
+        {{{ 0.502,0.502,0.502,1 }}}, // color_item
+        {{{ 0.706, 0.706, 0.706,1 }}}, // color_inner
+        {{{ 0.6, 0.6, 0.6,1 }}}, // color_inner_selected
+        BND_COLOR_TEXT, // color_text
+        BND_COLOR_TEXT_SELECTED, // color_text_selected
+        -20, // shade_top
+        0, // shade_down
+    },
+    // scrollBarTheme
+    {
+        {{{ 0.196,0.196,0.196,1 }}}, // color_outline
+        {{{ 0.502,0.502,0.502,1 }}}, // color_item
+        {{{ 0.314, 0.314, 0.314,0.706 }}}, // color_inner
+        {{{ 0.392, 0.392, 0.392,0.706 }}}, // color_inner_selected
+        BND_COLOR_TEXT, // color_text
+        BND_COLOR_TEXT_SELECTED, // color_text_selected
+        5, // shade_top
+        -5, // shade_down
+    },
+    // tooltipTheme
+    {
+        {{{ 0,0,0,1 }}}, // color_outline
+        {{{ 0.392,0.392,0.392,1 }}}, // color_item
+        {{{ 0.098, 0.098, 0.098, 0.902 }}}, // color_inner
+        {{{ 0.176, 0.176, 0.176, 0.902 }}}, // color_inner_selected
+        {{{ 0.627, 0.627, 0.627, 1 }}}, // color_text
+        BND_COLOR_TEXT_SELECTED, // color_text_selected
+        0, // shade_top
+        0, // shade_down
+    },
+    // menuTheme
+    {
+        {{{ 0,0,0,1 }}}, // color_outline
+        {{{ 0.392,0.392,0.392,1 }}}, // color_item
+        {{{ 0.098, 0.098, 0.098, 0.902 }}}, // color_inner
+        {{{ 0.176, 0.176, 0.176, 0.902 }}}, // color_inner_selected
+        {{{ 0.627, 0.627, 0.627, 1 }}}, // color_text
+        BND_COLOR_TEXT_SELECTED, // color_text_selected
+        0, // shade_top
+        0, // shade_down
+    },
+    // menuItemTheme
+    {
+        {{{ 0,0,0,1 }}}, // color_outline
+        {{{ 0.675,0.675,0.675,0.502 }}}, // color_item
+        {{{ 0,0,0,0 }}}, // color_inner
+        {{{ 0.337,0.502,0.761,1 }}}, // color_inner_selected
+        BND_COLOR_TEXT_SELECTED, // color_text
+        BND_COLOR_TEXT, // color_text_selected
+        38, // shade_top
+        0, // shade_down
+    },
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+void bndSetTheme(BNDtheme theme) {
+    bnd_theme = theme;
+}
+
+const BNDtheme *bndGetTheme() {
+    return &bnd_theme;
+}
+
+// the handle to the image containing the icon sheet
+static int bnd_icon_image = -1;
+
+void bndSetIconImage(int image) {
+    bnd_icon_image = image;
+}
+
+// the handle to the UI font
+static int bnd_font = -1;
+
+void bndSetFont(int font) {
+    bnd_font = font;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void bndLabel(NVGcontext *ctx,
+    float x, float y, float w, float h, int iconid, const char *label) {
+    bndIconLabelValue(ctx,x,y,w,h,iconid,
+        bnd_theme.regularTheme.textColor, BND_LEFT,
+        BND_LABEL_FONT_SIZE, label, NULL);
+}
+
+void bndToolButton(NVGcontext *ctx,
+    float x, float y, float w, float h, int flags, BNDwidgetState state,
+    int iconid, const char *label) {
+    float cr[4];
+    NVGcolor shade_top, shade_down;
+
+    bndSelectCorners(cr, BND_TOOL_RADIUS, flags);
+    bndBevelInset(ctx,x,y,w,h,cr[2],cr[3]);
+    bndInnerColors(&shade_top, &shade_down, &bnd_theme.toolTheme, state, 1);
+    bndInnerBox(ctx,x,y,w,h,cr[0],cr[1],cr[2],cr[3], shade_top, shade_down);
+    bndOutlineBox(ctx,x,y,w,h,cr[0],cr[1],cr[2],cr[3],
+        bndTransparent(bnd_theme.toolTheme.outlineColor));
+    bndIconLabelValue(ctx,x,y,w,h,iconid,
+        bndTextColor(&bnd_theme.toolTheme, state), BND_CENTER,
+        BND_LABEL_FONT_SIZE, label, NULL);
+}
+
+void bndRadioButton(NVGcontext *ctx,
+    float x, float y, float w, float h, int flags, BNDwidgetState state,
+    int iconid, const char *label) {
+    float cr[4];
+    NVGcolor shade_top, shade_down;
+
+    bndSelectCorners(cr, BND_OPTION_RADIUS, flags);
+    bndBevelInset(ctx,x,y,w,h,cr[2],cr[3]);
+    bndInnerColors(&shade_top, &shade_down, &bnd_theme.radioTheme, state, 1);
+    bndInnerBox(ctx,x,y,w,h,cr[0],cr[1],cr[2],cr[3], shade_top, shade_down);
+    bndOutlineBox(ctx,x,y,w,h,cr[0],cr[1],cr[2],cr[3],
+        bndTransparent(bnd_theme.radioTheme.outlineColor));
+    bndIconLabelValue(ctx,x,y,w,h,iconid,
+        bndTextColor(&bnd_theme.radioTheme, state), BND_CENTER,
+        BND_LABEL_FONT_SIZE, label, NULL);
+}
+
+void bndTextField(NVGcontext *ctx,
+    float x, float y, float w, float h, int flags, BNDwidgetState state,
+    int iconid, const char *text, int cbegin, int cend) {
+    float cr[4];
+    NVGcolor shade_top, shade_down;
+
+    bndSelectCorners(cr, BND_TEXT_RADIUS, flags);
+    bndBevelInset(ctx,x,y,w,h,cr[2],cr[3]);
+    bndInnerColors(&shade_top, &shade_down, &bnd_theme.textFieldTheme, state, 0);
+    bndInnerBox(ctx,x,y,w,h,cr[0],cr[1],cr[2],cr[3], shade_top, shade_down);
+    bndOutlineBox(ctx,x,y,w,h,cr[0],cr[1],cr[2],cr[3],
+        bndTransparent(bnd_theme.textFieldTheme.outlineColor));
+    if (state != BND_ACTIVE) {
+        cend = -1;
+    }
+    bndIconLabelCaret(ctx,x,y,w,h,iconid,
+        bndTextColor(&bnd_theme.textFieldTheme, state), BND_LABEL_FONT_SIZE,
+        text, bnd_theme.textFieldTheme.itemColor, cbegin, cend);
+}
+
+void bndOptionButton(NVGcontext *ctx,
+    float x, float y, float w, float h, BNDwidgetState state,
+    const char *label) {
+    float ox, oy;
+    NVGcolor shade_top, shade_down;
+
+    ox = x;
+    oy = y+h-BND_OPTION_HEIGHT-3;
+
+    bndBevelInset(ctx,ox,oy,
+        BND_OPTION_WIDTH,BND_OPTION_HEIGHT,
+        BND_OPTION_RADIUS,BND_OPTION_RADIUS);
+    bndInnerColors(&shade_top, &shade_down, &bnd_theme.optionTheme, state, 1);
+    bndInnerBox(ctx,ox,oy,
+        BND_OPTION_WIDTH,BND_OPTION_HEIGHT,
+        BND_OPTION_RADIUS,BND_OPTION_RADIUS,BND_OPTION_RADIUS,BND_OPTION_RADIUS,
+        shade_top, shade_down);
+    bndOutlineBox(ctx,ox,oy,
+        BND_OPTION_WIDTH,BND_OPTION_HEIGHT,
+        BND_OPTION_RADIUS,BND_OPTION_RADIUS,BND_OPTION_RADIUS,BND_OPTION_RADIUS,
+        bndTransparent(bnd_theme.optionTheme.outlineColor));
+    if (state == BND_ACTIVE) {
+        bndCheck(ctx,ox,oy, bndTransparent(bnd_theme.optionTheme.itemColor));
+    }
+    bndIconLabelValue(ctx,x+12,y,w-12,h,-1,
+        bndTextColor(&bnd_theme.optionTheme, state), BND_LEFT,
+        BND_LABEL_FONT_SIZE, label, NULL);
+}
+
+void bndChoiceButton(NVGcontext *ctx,
+    float x, float y, float w, float h, int flags, BNDwidgetState state,
+    int iconid, const char *label) {
+    float cr[4];
+    NVGcolor shade_top, shade_down;
+
+    bndSelectCorners(cr, BND_OPTION_RADIUS, flags);
+    bndBevelInset(ctx,x,y,w,h,cr[2],cr[3]);
+    bndInnerColors(&shade_top, &shade_down, &bnd_theme.choiceTheme, state, 1);
+    bndInnerBox(ctx,x,y,w,h,cr[0],cr[1],cr[2],cr[3], shade_top, shade_down);
+    bndOutlineBox(ctx,x,y,w,h,cr[0],cr[1],cr[2],cr[3],
+        bndTransparent(bnd_theme.choiceTheme.outlineColor));
+    bndIconLabelValue(ctx,x,y,w,h,iconid,
+        bndTextColor(&bnd_theme.choiceTheme, state), BND_LEFT,
+        BND_LABEL_FONT_SIZE, label, NULL);
+    bndUpDownArrow(ctx,x+w-10,y+10,5,
+        bndTransparent(bnd_theme.choiceTheme.itemColor));
+}
+
+void bndNumberField(NVGcontext *ctx,
+    float x, float y, float w, float h, int flags, BNDwidgetState state,
+    const char *label, const char *value) {
+    float cr[4];
+    NVGcolor shade_top, shade_down;
+
+    bndSelectCorners(cr, BND_NUMBER_RADIUS, flags);
+    bndBevelInset(ctx,x,y,w,h,cr[2],cr[3]);
+    bndInnerColors(&shade_top, &shade_down, &bnd_theme.numberFieldTheme, state, 0);
+    bndInnerBox(ctx,x,y,w,h,cr[0],cr[1],cr[2],cr[3], shade_top, shade_down);
+    bndOutlineBox(ctx,x,y,w,h,cr[0],cr[1],cr[2],cr[3],
+        bndTransparent(bnd_theme.numberFieldTheme.outlineColor));
+    bndIconLabelValue(ctx,x,y,w,h,-1,
+        bndTextColor(&bnd_theme.numberFieldTheme, state), BND_CENTER,
+        BND_LABEL_FONT_SIZE, label, value);
+    bndArrow(ctx,x+8,y+10,-BND_NUMBER_ARROW_SIZE,
+        bndTransparent(bnd_theme.numberFieldTheme.itemColor));
+    bndArrow(ctx,x+w-8,y+10,BND_NUMBER_ARROW_SIZE,
+        bndTransparent(bnd_theme.numberFieldTheme.itemColor));
+}
+
+void bndSlider(NVGcontext *ctx,
+    float x, float y, float w, float h, int flags, BNDwidgetState state,
+    float progress, const char *label, const char *value) {
+    float cr[4];
+    NVGcolor shade_top, shade_down;
+
+    bndSelectCorners(cr, BND_NUMBER_RADIUS, flags);
+    bndBevelInset(ctx,x,y,w,h,cr[2],cr[3]);
+    bndInnerColors(&shade_top, &shade_down, &bnd_theme.sliderTheme, state, 0);
+    bndInnerBox(ctx,x,y,w,h,cr[0],cr[1],cr[2],cr[3], shade_top, shade_down);
+
+    if (state == BND_ACTIVE) {
+        shade_top = bndOffsetColor(
+            bnd_theme.sliderTheme.itemColor, bnd_theme.sliderTheme.shadeTop);
+        shade_down = bndOffsetColor(
+            bnd_theme.sliderTheme.itemColor, bnd_theme.sliderTheme.shadeDown);
+    } else {
+        shade_top = bndOffsetColor(
+            bnd_theme.sliderTheme.itemColor, bnd_theme.sliderTheme.shadeDown);
+        shade_down = bndOffsetColor(
+            bnd_theme.sliderTheme.itemColor, bnd_theme.sliderTheme.shadeTop);
+    }
+    nvgScissor(ctx,x,y,8+(w-8)*bnd_clamp(progress,0,1),h);
+    bndInnerBox(ctx,x,y,w,h,cr[0],cr[1],cr[2],cr[3], shade_top, shade_down);
+    nvgResetScissor(ctx);
+
+    bndOutlineBox(ctx,x,y,w,h,cr[0],cr[1],cr[2],cr[3],
+        bndTransparent(bnd_theme.sliderTheme.outlineColor));
+    bndIconLabelValue(ctx,x,y,w,h,-1,
+        bndTextColor(&bnd_theme.sliderTheme, state), BND_CENTER,
+        BND_LABEL_FONT_SIZE, label, value);
+}
+
+void bndScrollBar(NVGcontext *ctx,
+    float x, float y, float w, float h, BNDwidgetState state,
+    float offset, float size) {
+
+    bndBevelInset(ctx,x,y,w,h,
+        BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS);
+    bndInnerBox(ctx,x,y,w,h,
+        BND_SCROLLBAR_RADIUS,BND_SCROLLBAR_RADIUS,
+        BND_SCROLLBAR_RADIUS,BND_SCROLLBAR_RADIUS,
+        bndOffsetColor(
+            bnd_theme.scrollBarTheme.innerColor, 3*bnd_theme.scrollBarTheme.shadeDown),
+        bndOffsetColor(
+            bnd_theme.scrollBarTheme.innerColor, 3*bnd_theme.scrollBarTheme.shadeTop));
+    bndOutlineBox(ctx,x,y,w,h,
+        BND_SCROLLBAR_RADIUS,BND_SCROLLBAR_RADIUS,
+        BND_SCROLLBAR_RADIUS,BND_SCROLLBAR_RADIUS,
+        bndTransparent(bnd_theme.scrollBarTheme.outlineColor));
+
+    NVGcolor itemColor = bndOffsetColor(
+        bnd_theme.scrollBarTheme.itemColor,
+        (state == BND_ACTIVE)?BND_SCROLLBAR_ACTIVE_SHADE:0);
+
+    bndScrollHandleRect(&x,&y,&w,&h,offset,size);
+
+    bndInnerBox(ctx,x,y,w,h,
+        BND_SCROLLBAR_RADIUS,BND_SCROLLBAR_RADIUS,
+        BND_SCROLLBAR_RADIUS,BND_SCROLLBAR_RADIUS,
+        bndOffsetColor(
+            itemColor, 3*bnd_theme.scrollBarTheme.shadeTop),
+        bndOffsetColor(
+            itemColor, 3*bnd_theme.scrollBarTheme.shadeDown));
+    bndOutlineBox(ctx,x,y,w,h,
+        BND_SCROLLBAR_RADIUS,BND_SCROLLBAR_RADIUS,
+        BND_SCROLLBAR_RADIUS,BND_SCROLLBAR_RADIUS,
+        bndTransparent(bnd_theme.scrollBarTheme.outlineColor));
+}
+
+void bndMenuBackground(NVGcontext *ctx,
+    float x, float y, float w, float h, int flags) {
+    float cr[4];
+    NVGcolor shade_top, shade_down;
+
+    bndSelectCorners(cr, BND_MENU_RADIUS, flags);
+    bndInnerColors(&shade_top, &shade_down, &bnd_theme.menuTheme,
+        BND_DEFAULT, 0);
+    bndInnerBox(ctx,x,y,w,h+1,cr[0],cr[1],cr[2],cr[3], shade_top, shade_down);
+    bndOutlineBox(ctx,x,y,w,h+1,cr[0],cr[1],cr[2],cr[3],
+        bndTransparent(bnd_theme.menuTheme.outlineColor));
+    bndDropShadow(ctx,x,y,w,h,BND_MENU_RADIUS,
+        BND_SHADOW_FEATHER,BND_SHADOW_ALPHA);
+}
+
+void bndTooltipBackground(NVGcontext *ctx, float x, float y, float w, float h) {
+    NVGcolor shade_top, shade_down;
+
+    bndInnerColors(&shade_top, &shade_down, &bnd_theme.tooltipTheme,
+        BND_DEFAULT, 0);
+    bndInnerBox(ctx,x,y,w,h+1,
+        BND_MENU_RADIUS,BND_MENU_RADIUS,BND_MENU_RADIUS,BND_MENU_RADIUS,
+        shade_top, shade_down);
+    bndOutlineBox(ctx,x,y,w,h+1,
+        BND_MENU_RADIUS,BND_MENU_RADIUS,BND_MENU_RADIUS,BND_MENU_RADIUS,
+        bndTransparent(bnd_theme.tooltipTheme.outlineColor));
+    bndDropShadow(ctx,x,y,w,h,BND_MENU_RADIUS,
+        BND_SHADOW_FEATHER,BND_SHADOW_ALPHA);
+}
+
+void bndMenuLabel(NVGcontext *ctx,
+    float x, float y, float w, float h, int iconid, const char *label) {
+    bndIconLabelValue(ctx,x,y,w,h,iconid,
+        bnd_theme.menuTheme.textColor, BND_LEFT,
+        BND_LABEL_FONT_SIZE, label, NULL);
+}
+
+void bndMenuItem(NVGcontext *ctx,
+    float x, float y, float w, float h, BNDwidgetState state,
+    int iconid, const char *label) {
+    if (state != BND_DEFAULT) {
+        bndInnerBox(ctx,x,y,w,h,0,0,0,0,
+            bndOffsetColor(bnd_theme.menuItemTheme.innerSelectedColor,
+                bnd_theme.menuItemTheme.shadeTop),
+            bndOffsetColor(bnd_theme.menuItemTheme.innerSelectedColor,
+                bnd_theme.menuItemTheme.shadeDown));
+        state = BND_ACTIVE;
+    }
+    bndIconLabelValue(ctx,x,y,w,h,iconid,
+        bndTextColor(&bnd_theme.menuItemTheme, state), BND_LEFT,
+        BND_LABEL_FONT_SIZE, label, NULL);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void bndRoundedBox(NVGcontext *ctx, float x, float y, float w, float h,
+    float cr0, float cr1, float cr2, float cr3) {
+    float d;
+
+    w = fmaxf(0, w);
+    h = fmaxf(0, h);
+    d = fminf(w, h);
+
+    nvgMoveTo(ctx, x,y+h*0.5f);
+    nvgArcTo(ctx, x,y, x+w,y, fminf(cr0, d/2));
+    nvgArcTo(ctx, x+w,y, x+w,y+h, fminf(cr1, d/2));
+    nvgArcTo(ctx, x+w,y+h, x,y+h, fminf(cr2, d/2));
+    nvgArcTo(ctx, x,y+h, x,y, fminf(cr3, d/2));
+    nvgClosePath(ctx);
+}
+
+NVGcolor bndTransparent(NVGcolor color) {
+    color.a *= BND_TRANSPARENT_ALPHA;
+    return color;
+}
+
+NVGcolor bndOffsetColor(NVGcolor color, int delta) {
+    float offset = (float)delta / 255.0f;
+    return delta?(
+        nvgRGBAf(
+            bnd_clamp(color.r+offset,0,1),
+            bnd_clamp(color.g+offset,0,1),
+            bnd_clamp(color.b+offset,0,1),
+            color.a)
+    ):color;
+}
+
+void bndBevelInset(NVGcontext *ctx, float x, float y, float w, float h,
+    float cr2, float cr3) {
+    float d;
+
+    y -= 0.5f;
+    d = fminf(w, h);
+    cr2 = fminf(cr2, d/2);
+    cr3 = fminf(cr3, d/2);
+
+    nvgBeginPath(ctx);
+    nvgMoveTo(ctx, x+w,y+h-cr2);
+    nvgArcTo(ctx, x+w,y+h, x,y+h, cr2);
+    nvgArcTo(ctx, x,y+h, x,y, cr3);
+
+    NVGcolor bevelColor = bndOffsetColor(bnd_theme.backgroundColor,
+        BND_BEVEL_SHADE);
+
+    nvgStrokeWidth(ctx, 1);
+    nvgStrokePaint(ctx,
+        nvgLinearGradient(ctx,
+            x,y+h-fmaxf(cr2,cr3)-1,
+            x,y+h-1,
+        nvgRGBAf(bevelColor.r, bevelColor.g, bevelColor.b, 0),
+        bevelColor));
+    nvgStroke(ctx);
+}
+
+void bndBackground(NVGcontext *ctx, float x, float y, float w, float h) {
+    nvgBeginPath(ctx);
+    nvgRect(ctx, x, y, w, h);
+    nvgFillColor(ctx, bnd_theme.backgroundColor);
+    nvgFill(ctx);
+}
+
+void bndIcon(NVGcontext *ctx, float x, float y, int iconid) {
+    int ix, iy, u, v;
+    if (bnd_icon_image < 0) return; // no icons loaded
+
+    ix = iconid & 0xff;
+    iy = (iconid>>8) & 0xff;
+    u = BND_ICON_SHEET_OFFSET_X + ix*BND_ICON_SHEET_GRID;
+    v = BND_ICON_SHEET_OFFSET_Y + iy*BND_ICON_SHEET_GRID;
+
+    nvgBeginPath(ctx);
+    nvgRect(ctx,x,y,BND_ICON_SHEET_RES,BND_ICON_SHEET_RES);
+    nvgFillPaint(ctx,
+        nvgImagePattern(ctx,x-u,y-v,
+        BND_ICON_SHEET_WIDTH,
+        BND_ICON_SHEET_HEIGHT,
+        0,bnd_icon_image,0));
+    nvgFill(ctx);
+}
+
+void bndDropShadow(NVGcontext *ctx, float x, float y, float w, float h,
+    float r, float feather, float alpha) {
+
+    nvgBeginPath(ctx);
+    y += feather;
+    h -= feather;
+
+    nvgMoveTo(ctx, x-feather, y-feather);
+    nvgLineTo(ctx, x, y-feather);
+    nvgLineTo(ctx, x, y+h-feather);
+    nvgArcTo(ctx, x,y+h,x+r,y+h,r);
+    nvgArcTo(ctx, x+w,y+h,x+w,y+h-r,r);
+    nvgLineTo(ctx, x+w, y-feather);
+    nvgLineTo(ctx, x+w+feather, y-feather);
+    nvgLineTo(ctx, x+w+feather, y+h+feather);
+    nvgLineTo(ctx, x-feather, y+h+feather);
+    nvgClosePath(ctx);
+
+    nvgFillPaint(ctx, nvgBoxGradient(ctx,
+        x - feather*0.5f,y - feather*0.5f,
+        w + feather,h+feather,
+        r+feather*0.5f,
+        feather,
+        nvgRGBAf(0,0,0,alpha*alpha),
+        nvgRGBAf(0,0,0,0)));
+    nvgFill(ctx);
+}
+
+void bndInnerBox(NVGcontext *ctx, float x, float y, float w, float h,
+    float cr0, float cr1, float cr2, float cr3,
+    NVGcolor shade_top, NVGcolor shade_down) {
+    nvgBeginPath(ctx);
+    bndRoundedBox(ctx,x+1,y+1,w-2,h-3,
+        fmaxf(0,cr0-1),fmaxf(0,cr1-1),fmaxf(0,cr2-1),fmaxf(0,cr3-1));
+    nvgFillPaint(ctx,((h-2)>w)?
+        nvgLinearGradient(ctx,x,y,x+w,y,shade_top,shade_down):
+        nvgLinearGradient(ctx,x,y,x,y+h,shade_top,shade_down));
+    nvgFill(ctx);
+}
+
+void bndOutlineBox(NVGcontext *ctx, float x, float y, float w, float h,
+    float cr0, float cr1, float cr2, float cr3, NVGcolor color) {
+    nvgBeginPath(ctx);
+    bndRoundedBox(ctx,x+0.5f,y+0.5f,w-1,h-2,cr0,cr1,cr2,cr3);
+    nvgStrokeColor(ctx,color);
+    nvgStrokeWidth(ctx,1);
+    nvgStroke(ctx);
+}
+
+void bndSelectCorners(float *radiuses, float r, int flags) {
+    radiuses[0] = (flags & BND_CORNER_TOP_LEFT)?0:r;
+    radiuses[1] = (flags & BND_CORNER_TOP_RIGHT)?0:r;
+    radiuses[2] = (flags & BND_CORNER_DOWN_RIGHT)?0:r;
+    radiuses[3] = (flags & BND_CORNER_DOWN_LEFT)?0:r;
+}
+
+void bndInnerColors(
+    NVGcolor *shade_top, NVGcolor *shade_down,
+    const BNDwidgetTheme *theme, BNDwidgetState state, int flipActive) {
+
+    switch(state) {
+    default:
+    case BND_DEFAULT: {
+        *shade_top = bndOffsetColor(theme->innerColor, theme->shadeTop);
+        *shade_down = bndOffsetColor(theme->innerColor, theme->shadeDown);
+    } break;
+    case BND_HOVER: {
+        NVGcolor color = bndOffsetColor(theme->innerColor, BND_HOVER_SHADE);
+        *shade_top = bndOffsetColor(color, theme->shadeTop);
+        *shade_down = bndOffsetColor(color, theme->shadeDown);
+    } break;
+    case BND_ACTIVE: {
+        *shade_top = bndOffsetColor(theme->innerSelectedColor,
+            flipActive?theme->shadeDown:theme->shadeTop);
+        *shade_down = bndOffsetColor(theme->innerSelectedColor,
+            flipActive?theme->shadeTop:theme->shadeDown);
+    } break;
+    }
+}
+
+NVGcolor bndTextColor(const BNDwidgetTheme *theme, BNDwidgetState state) {
+    return (state == BND_ACTIVE)?theme->textSelectedColor:theme->textColor;
+}
+
+void bndIconLabelValue(NVGcontext *ctx, float x, float y, float w, float h,
+    int iconid, NVGcolor color, int align, float fontsize, const char *label,
+    const char *value) {
+    float pleft = BND_PAD_LEFT;
+    if (label) {
+        if (iconid >= 0) {
+            bndIcon(ctx,x+4,y+2,iconid);
+            pleft += BND_ICON_SHEET_RES;
+        }
+
+        if (bnd_font < 0) return;
+        nvgFontFaceId(ctx, bnd_font);
+        nvgFontSize(ctx, fontsize);
+        nvgBeginPath(ctx);
+        nvgFillColor(ctx, color);
+        if (value) {
+            float label_width = nvgTextBounds(ctx, 1, 1, label, NULL, NULL);
+            float sep_width = nvgTextBounds(ctx, 1, 1,
+                BND_LABEL_SEPARATOR, NULL, NULL);
+
+            nvgTextAlign(ctx, NVG_ALIGN_LEFT|NVG_ALIGN_BASELINE);
+            x += pleft;
+            if (align == BND_CENTER) {
+                float width = label_width + sep_width
+                    + nvgTextBounds(ctx, 1, 1, value, NULL, NULL);
+                x += ((w-BND_PAD_RIGHT-pleft)-width)*0.5f;
+            }
+            y += h-6;
+            nvgText(ctx, x, y, label, NULL);
+            x += label_width;
+            nvgText(ctx, x, y, BND_LABEL_SEPARATOR, NULL);
+            x += sep_width;
+            nvgText(ctx, x, y, value, NULL);
+        } else {
+            nvgTextAlign(ctx,
+                (align==BND_LEFT)?(NVG_ALIGN_LEFT|NVG_ALIGN_BASELINE):
+                (NVG_ALIGN_CENTER|NVG_ALIGN_BASELINE));
+            nvgTextBox(ctx,x+pleft,y+h-6,w-BND_PAD_RIGHT-pleft,label, NULL);
+        }
+    } else if (iconid >= 0) {
+        bndIcon(ctx,x+2,y+2,iconid);
+    }
+}
+
+void bndIconLabelCaret(NVGcontext *ctx, float x, float y, float w, float h,
+    int iconid, NVGcolor color, float fontsize, const char *label,
+    NVGcolor caretcolor, int cbegin, int cend) {
+    float bounds[4];
+    float pleft = BND_TEXT_RADIUS;
+    if (!label) return;
+    if (iconid >= 0) {
+        bndIcon(ctx,x+4,y+2,iconid);
+        pleft += BND_ICON_SHEET_RES;
+    }
+
+    if (bnd_font < 0) return;
+
+    x+=pleft;
+    y+=h-6;
+
+    nvgFontFaceId(ctx, bnd_font);
+    nvgFontSize(ctx, fontsize);
+    nvgTextAlign(ctx, NVG_ALIGN_LEFT|NVG_ALIGN_BASELINE);
+
+    if (cend >= cbegin) {
+        float c0,c1;
+        const char *cb;const char *ce;
+        static NVGglyphPosition glyphs[BND_MAX_GLYPHS];
+        int nglyphs = nvgTextGlyphPositions(
+            ctx, x, y, label, label+cend+1, glyphs, BND_MAX_GLYPHS);
+        c0=glyphs[0].x;
+        c1=glyphs[nglyphs-1].x;
+        cb = label+cbegin; ce = label+cend;
+        // TODO: this is slow
+        for (int i=0; i < nglyphs; ++i) {
+            if (glyphs[i].str == cb)
+                c0 = glyphs[i].x;
+            if (glyphs[i].str == ce)
+                c1 = glyphs[i].x;
+        }
+
+        nvgTextBounds(ctx,x,y,label,NULL, bounds);
+        nvgBeginPath(ctx);
+        if (cbegin == cend) {
+            nvgFillColor(ctx, nvgRGBf(0.337,0.502,0.761));
+            nvgRect(ctx, c0-1, bounds[1], 2, bounds[3]-bounds[1]);
+        } else {
+            nvgFillColor(ctx, caretcolor);
+            nvgRect(ctx, c0-1, bounds[1], c1-c0+1, bounds[3]-bounds[1]);
+        }
+        nvgFill(ctx);
+    }
+
+    nvgBeginPath(ctx);
+    nvgFillColor(ctx, color);
+    nvgTextBox(ctx,x,y,w-BND_TEXT_RADIUS-pleft,label, NULL);
+}
+
+void bndCheck(NVGcontext *ctx, float ox, float oy, NVGcolor color) {
+    nvgBeginPath(ctx);
+    nvgStrokeWidth(ctx,2);
+    nvgStrokeColor(ctx,color);
+    nvgLineCap(ctx,NVG_BUTT);
+    nvgLineJoin(ctx,NVG_MITER);
+    nvgMoveTo(ctx,ox+4,oy+5);
+    nvgLineTo(ctx,ox+7,oy+8);
+    nvgLineTo(ctx,ox+14,oy+1);
+    nvgStroke(ctx);
+}
+
+void bndArrow(NVGcontext *ctx, float x, float y, float s, NVGcolor color) {
+    nvgBeginPath(ctx);
+    nvgMoveTo(ctx,x,y);
+    nvgLineTo(ctx,x-s,y+s);
+    nvgLineTo(ctx,x-s,y-s);
+    nvgClosePath(ctx);
+    nvgFillColor(ctx,color);
+    nvgFill(ctx);
+}
+
+void bndUpDownArrow(NVGcontext *ctx, float x, float y, float s, NVGcolor color) {
+    float w;
+
+    nvgBeginPath(ctx);
+    w = 1.1f*s;
+    nvgMoveTo(ctx,x,y-1);
+    nvgLineTo(ctx,x+0.5*w,y-s-1);
+    nvgLineTo(ctx,x+w,y-1);
+    nvgClosePath(ctx);
+    nvgMoveTo(ctx,x,y+1);
+    nvgLineTo(ctx,x+0.5*w,y+s+1);
+    nvgLineTo(ctx,x+w,y+1);
+    nvgClosePath(ctx);
+    nvgFillColor(ctx,color);
+    nvgFill(ctx);
+}
+
+void bndScrollHandleRect(float *x, float *y, float *w, float *h,
+    float offset, float size) {
+    size = bnd_clamp(size,0,1);
+    offset = bnd_clamp(offset,0,1);
+    if ((*h) > (*w)) {
+        float hs = fmaxf(size*(*h), (*w)+1);
+        *y = (*y) + ((*h)-hs)*offset;
+        *h = hs;
+    } else {
+        float ws = fmaxf(size*(*w), (*h)-1);
+        *x = (*x) + ((*w)-ws)*offset;
+        *w = ws;
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef BND_INLINE
+#undef BND_INLINE
+#endif
+
+#endif // BLENDISH_IMPLEMENTATION

+ 181 - 14
examples/20-nanovg/nanovg.cpp

@@ -32,6 +32,14 @@
 #include "entry/entry.h"
 #include "entry/entry.h"
 #include "nanovg/nanovg.h"
 #include "nanovg/nanovg.h"
 
 
+#ifdef BX_COMPILER_MSVC
+	#pragma warning (disable: 4305) // Switch off truncation from double to float.
+	#pragma warning (disable: 4244) // Switch off conversion from int to float, posssible loss of data.
+#endif
+
+#define BLENDISH_IMPLEMENTATION
+#include "blendish.h"
+
 #define ICON_SEARCH 0x1F50D
 #define ICON_SEARCH 0x1F50D
 #define ICON_CIRCLED_CROSS 0x2716
 #define ICON_CIRCLED_CROSS 0x2716
 #define ICON_CHEVRON_RIGHT 0xE75E
 #define ICON_CHEVRON_RIGHT 0xE75E
@@ -778,9 +786,158 @@ void drawLines(struct NVGcontext* vg, float x, float y, float w, float h, float
 	nvgRestore(vg);
 	nvgRestore(vg);
 }
 }
 
 
+void drawBlendish(struct NVGcontext* _vg, int _x, int _y, float _w, float _h, float _t)
+{
+	// Don't draw background.
+	//bndBackground(_vg, float(_x-10), float(_y-10), _w, _h);
+
+	int x = _x;
+	int y = _y;
+
+	bndToolButton(_vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT, BND_ICONID(6,3),"Default");
+	y += 25;
+	bndToolButton(_vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER, BND_ICONID(6,3),"Hovered");
+	y += 25;
+	bndToolButton(_vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE, BND_ICONID(6,3),"Active");
+
+	y += 40;
+	bndRadioButton(_vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT, -1,"Default");
+	y += 25;
+	bndRadioButton(_vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER, -1,"Hovered");
+	y += 25;
+	bndRadioButton(_vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE, -1,"Active");
+
+	y += 25;
+	bndLabel(_vg,x,y,120,BND_WIDGET_HEIGHT,-1,"Label:");
+	y += BND_WIDGET_HEIGHT;
+	bndChoiceButton(_vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT, -1, "Default");
+	y += 25;
+	bndChoiceButton(_vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER, -1, "Hovered");
+	y += 25;
+	bndChoiceButton(_vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE, -1, "Active");
+
+	y += 25;
+	int ry = y;
+	int rx = x;
+
+	y = _y;
+	x += 130;
+	bndOptionButton(_vg,x,y,120,BND_WIDGET_HEIGHT,BND_DEFAULT,"Default");
+	y += 25;
+	bndOptionButton(_vg,x,y,120,BND_WIDGET_HEIGHT,BND_HOVER,"Hovered");
+	y += 25;
+	bndOptionButton(_vg,x,y,120,BND_WIDGET_HEIGHT,BND_ACTIVE,"Active");
+
+	y += 40;
+	bndNumberField(_vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_DOWN,BND_DEFAULT, "Top","100");
+	y += BND_WIDGET_HEIGHT-2;
+	bndNumberField(_vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT, "Center","100");
+	y += BND_WIDGET_HEIGHT-2;
+	bndNumberField(_vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_TOP,BND_DEFAULT, "Bottom","100");
+
+	int mx = x-30;
+	int my = y-12;
+	int mw = 120;
+	bndMenuBackground(_vg,mx,my,mw,120,BND_CORNER_TOP);
+	bndMenuLabel(_vg,mx,my,mw,BND_WIDGET_HEIGHT,-1,"Menu Title");
+	my += BND_WIDGET_HEIGHT-2;
+	bndMenuItem(_vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_DEFAULT, BND_ICONID(17,3),"Default");
+	my += BND_WIDGET_HEIGHT-2;
+	bndMenuItem(_vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_HOVER, BND_ICONID(18,3),"Hovered");
+	my += BND_WIDGET_HEIGHT-2;
+	bndMenuItem(_vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_ACTIVE, BND_ICONID(19,3),"Active");
+
+	y = _y;
+	x += 130;
+	int ox = x;
+	bndNumberField(_vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT, "Default","100");
+	y += 25;
+	bndNumberField(_vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER, "Hovered","100");
+	y += 25;
+	bndNumberField(_vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE, "Active","100");
+
+	y += 40;
+	bndRadioButton(_vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,BND_DEFAULT, -1,"One");
+	x += 60-1;
+	bndRadioButton(_vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT, -1,"Two");
+	x += 60-1;
+	bndRadioButton(_vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT, -1,"Three");
+	x += 60-1;
+	bndRadioButton(_vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,BND_ACTIVE, -1,"Butts");
+
+	x = ox;
+	y += 40;
+	float progress_value = fmodf(_t/10.0,1.0);
+	char progress_label[32];
+	sprintf(progress_label, "%d%%", int(progress_value*100+0.5f));
+	bndSlider(_vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT, progress_value,"Default",progress_label);
+	y += 25;
+	bndSlider(_vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER, progress_value,"Hovered",progress_label);
+	y += 25;
+	bndSlider(_vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE, progress_value,"Active",progress_label);
+
+	int rw = x+240-rx;
+	float s_offset = sinf(_t/2.0)*0.5+0.5;
+	float s_size = cosf(_t/3.11)*0.5+0.5;
+
+	bndScrollBar(_vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_DEFAULT,s_offset,s_size);
+	ry += 20;
+	bndScrollBar(_vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_HOVER,s_offset,s_size);
+	ry += 20;
+	bndScrollBar(_vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_ACTIVE,s_offset,s_size);
+
+	const char edit_text[] = "The quick brown fox";
+	int textlen = int(strlen(edit_text)+1);
+	int t = int(_t*2);
+	int idx1 = (t/textlen)%textlen;
+	int idx2 = idx1 + (t%(textlen-idx1));
+
+	ry += 25;
+	bndTextField(_vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT, -1, edit_text, idx1, idx2);
+	ry += 25;
+	bndTextField(_vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER, -1, edit_text, idx1, idx2);
+	ry += 25;
+	bndTextField(_vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE, -1, edit_text, idx1, idx2);
+
+	rx += rw + 20;
+	ry = _y;
+	bndScrollBar(_vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_DEFAULT,s_offset,s_size);
+	rx += 20;
+	bndScrollBar(_vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_HOVER,s_offset,s_size);
+	rx += 20;
+	bndScrollBar(_vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_ACTIVE,s_offset,s_size);
+
+	x = ox;
+	y += 40;
+	bndToolButton(_vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT, BND_DEFAULT,BND_ICONID(0,10),NULL);
+	x += BND_TOOL_WIDTH-1;
+	bndToolButton(_vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL, BND_DEFAULT,BND_ICONID(1,10),NULL);
+	x += BND_TOOL_WIDTH-1;
+	bndToolButton(_vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL, BND_DEFAULT,BND_ICONID(2,10),NULL);
+	x += BND_TOOL_WIDTH-1;
+	bndToolButton(_vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL, BND_DEFAULT,BND_ICONID(3,10),NULL);
+	x += BND_TOOL_WIDTH-1;
+	bndToolButton(_vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL, BND_DEFAULT,BND_ICONID(4,10),NULL);
+	x += BND_TOOL_WIDTH-1;
+	bndToolButton(_vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_LEFT, BND_DEFAULT,BND_ICONID(5,10),NULL);
+	x += BND_TOOL_WIDTH-1;
+	x += 5;
+	bndRadioButton(_vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT, BND_DEFAULT,BND_ICONID(0,11),NULL);
+	x += BND_TOOL_WIDTH-1;
+	bndRadioButton(_vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL, BND_DEFAULT,BND_ICONID(1,11),NULL);
+	x += BND_TOOL_WIDTH-1;
+	bndRadioButton(_vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL, BND_DEFAULT,BND_ICONID(2,11),NULL);
+	x += BND_TOOL_WIDTH-1;
+	bndRadioButton(_vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL, BND_DEFAULT,BND_ICONID(3,11),NULL);
+	x += BND_TOOL_WIDTH-1;
+	bndRadioButton(_vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL, BND_ACTIVE,BND_ICONID(4,11),NULL);
+	x += BND_TOOL_WIDTH-1;
+	bndRadioButton(_vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_LEFT, BND_DEFAULT,BND_ICONID(5,11),NULL);
+}
+
 struct DemoData
 struct DemoData
 {
 {
-	int fontNormal, fontBold, fontIcons; 
+	int fontNormal, fontBold, fontIcons;
 	int images[12];
 	int images[12];
 };
 };
 
 
@@ -983,18 +1140,16 @@ void drawWidths(struct NVGcontext* vg, float x, float y, float width)
 
 
 void renderDemo(struct NVGcontext* vg, float mx, float my, float width, float height, float t, int blowup, struct DemoData* data)
 void renderDemo(struct NVGcontext* vg, float mx, float my, float width, float height, float t, int blowup, struct DemoData* data)
 {
 {
-	float x,y,popy;
+	float x,y,popx,popy;
 
 
-	drawEyes(vg, width - 250, 50, 150, 100, mx, my, t);
-	drawParagraph(vg, width - 450, 50, 150, 100, mx, my);
+	drawEyes(vg, width-800, height-280, 150, 100, mx, my, t);
+	drawParagraph(vg, width - 550, 35, 150, 100, mx, my);
 	drawGraph(vg, 0, height/2, width, height/2, t);
 	drawGraph(vg, 0, height/2, width, height/2, t);
-	drawColorwheel(vg, width - 300, height - 300, 250.0f, 250.0f, t);
 
 
-	// Line joints
-	drawLines(vg, 50, height-50, 600, 50, t);
+	drawColorwheel(vg, width-350, 35, 250.0f, 250.0f, t);
 
 
-	// Line width;
-	drawWidths(vg, 10, 50, 30);
+	// Line joints
+	drawLines(vg, 50, height-50, 600, 35, t);
 
 
 	nvgSave(vg);
 	nvgSave(vg);
 	if (blowup)
 	if (blowup)
@@ -1003,12 +1158,18 @@ void renderDemo(struct NVGcontext* vg, float mx, float my, float width, float he
 		nvgScale(vg, 2.0f, 2.0f);
 		nvgScale(vg, 2.0f, 2.0f);
 	}
 	}
 
 
-	// Widgets
-	drawWindow(vg, "Widgets `n Stuff", 50, 50, 300, 400);
-	x = 60; y = 95;
+	// Line width.
+	drawWidths(vg, width-50, 35, 30);
+
+	// Widgets.
+	x = width-520; y = height-420;
+	drawWindow(vg, "Widgets `n Stuff", x, y, 300, 400);
+	x += 10;
+	y += 45;
 	drawSearchBox(vg, "Search", x,y,280,25);
 	drawSearchBox(vg, "Search", x,y,280,25);
 	y += 40;
 	y += 40;
 	drawDropDown(vg, "Effects", x,y,280,28);
 	drawDropDown(vg, "Effects", x,y,280,28);
+	popx = x + 300;
 	popy = y + 14;
 	popy = y + 14;
 	y += 45;
 	y += 45;
 
 
@@ -1034,7 +1195,10 @@ void renderDemo(struct NVGcontext* vg, float mx, float my, float width, float he
 	drawButton(vg, 0, "Cancel", x+170, y, 110, 28, nvgRGBA(0,0,0,0));
 	drawButton(vg, 0, "Cancel", x+170, y, 110, 28, nvgRGBA(0,0,0,0));
 
 
 	// Thumbnails box
 	// Thumbnails box
-	drawThumbnails(vg, 365, popy-30, 160, 300, data->images, 12, t);
+	drawThumbnails(vg, popx, popy-30, 160, 300, data->images, 12, t);
+
+	// Blendish
+	drawBlendish(vg, 10, 62, 600.0f, 420.0f, t);
 
 
 	nvgRestore(vg);
 	nvgRestore(vg);
 }
 }
@@ -1066,6 +1230,9 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 	DemoData data;
 	DemoData data;
 	loadDemoData(nvg, &data);
 	loadDemoData(nvg, &data);
 
 
+	bndSetFont(nvgCreateFont(nvg, "droidsans", "font/droidsans.ttf"));
+	bndSetIconImage(nvgCreateImage(nvg, "images/blender_icons16.png"));
+
 	int64_t timeOffset = bx::getHPCounter();
 	int64_t timeOffset = bx::getHPCounter();
 
 
 	entry::MouseState mouseState;
 	entry::MouseState mouseState;
@@ -1093,7 +1260,7 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 
 
 		nvgEndFrame(nvg);
 		nvgEndFrame(nvg);
 
 
-		// Advance to next frame. Rendering thread will be kicked to 
+		// Advance to next frame. Rendering thread will be kicked to
 		// process submitted rendering primitives.
 		// process submitted rendering primitives.
 		bgfx::frame();
 		bgfx::frame();
 	}
 	}

BIN
examples/20-nanovg/screenshot.png


BIN
examples/runtime/images/blender_icons16.png