1 /*
2 Blendish - Blender 2.5 UI based theming functions for NanoVega
3 
4 Copyright (c) 2014 Leonard Ritter <leonard.ritter@duangle.com>
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
23 */
24 // Fork developement, feature integration and new bugs:
25 // Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
26 /**
27 
28 Blendish is a small collection of drawing functions for NanoVega, designed to
29 replicate the look of the Blender 2.5+ User Interface. You can use these
30 functions to theme your UI library. Several metric constants for faithful
31 reproduction are also included.
32 
33 Blendish supports the original Blender icon sheet; As the licensing of Blenders
34 icons is unclear, they are not included in Blendishes repository, but a SVG
35 template, "icons_template.svg" is provided, which you can use to build your own
36 icon sheet.
37 
38 To use icons, you must first load the icon sheet using one of the
39 `nvgCreateImage*()` functions and then pass the image handle to `bndSetIconImage()`;
40 otherwise, no icons will be drawn. See `bndSetIconImage()` for more information.
41 
42 Blendish will not render text until a suitable UI font has been passed to
43 `bndSetFont()` has been called. See `bndSetFont()` for more information.
44 
45 
46 Drawbacks
47 
48 There is no support for varying dpi resolutions yet. The library is hardcoded
49 to the equivalent of 72 dpi in the Blender system settings.
50 
51 Support for label truncation is missing. Text rendering breaks when widgets are
52 too short to contain their labels.
53 
54 Version:
55 	Revision 6 (2014-09-21)
56 */
57 module arsd.blendish;
58 private:
59 
60 import arsd.nanovega;
61 version(aliced) {
62   import iv.meta;
63 } else {
64   private alias usize = size_t;
65   // i fear phobos!
66   private template Unqual(T) {
67          static if (is(T U ==          immutable U)) alias Unqual = U;
68     else static if (is(T U == shared inout const U)) alias Unqual = U;
69     else static if (is(T U == shared inout       U)) alias Unqual = U;
70     else static if (is(T U == shared       const U)) alias Unqual = U;
71     else static if (is(T U == shared             U)) alias Unqual = U;
72     else static if (is(T U ==        inout const U)) alias Unqual = U;
73     else static if (is(T U ==        inout       U)) alias Unqual = U;
74     else static if (is(T U ==              const U)) alias Unqual = U;
75     else alias Unqual = T;
76   }
77   private template isAnyCharType(T, bool unqual=false) {
78     static if (unqual) private alias UT = Unqual!T; else private alias UT = T;
79     enum isAnyCharType = is(UT == char) || is(UT == wchar) || is(UT == dchar);
80   }
81   private template isWideCharType(T, bool unqual=false) {
82     static if (unqual) private alias UT = Unqual!T; else private alias UT = T;
83     enum isWideCharType = is(UT == wchar) || is(UT == dchar);
84   }
85 }
86 
87 nothrow @trusted @nogc:
88 
89 
90 /** describes the theme used to draw a single widget or widget box;
91  * these values correspond to the same values that can be retrieved from
92  * the Theme panel in the Blender preferences */
93 public struct BNDwidgetTheme {
94   /// theme name
95   string name;
96   /// color of widget box outline
97   NVGColor outlineColor;
98   /// color of widget item (meaning changes depending on class)
99   NVGColor itemColor;
100   /// fill color of widget box
101   NVGColor innerColor;
102   /// fill color of widget box when active
103   NVGColor innerSelectedColor;
104   /// color of text label
105   NVGColor textColor;
106   /// color of text label when active
107   NVGColor textSelectedColor;
108   /// delta modifier for upper part of gradient (-100 to 100)
109   int shadeTop;
110   /// delta modifier for lower part of gradient (-100 to 100)
111   int shadeDown;
112   /// color of hovered text (if transparent, use `textSelectedColor`)
113   NVGColor textHoverColor;
114   /// color of caret for text field (if transparent, use `textColor`)
115   NVGColor textCaretColor;
116 }
117 
118 /// describes the theme used to draw nodes
119 public struct BNDnodeTheme {
120   /// theme name
121   string name;
122   /// inner color of selected node (and downarrow)
123   NVGColor nodeSelectedColor;
124   /// outline of wires
125   NVGColor wiresColor;
126   /// color of text label when active
127   NVGColor textSelectedColor;
128 
129   /// inner color of active node (and dragged wire)
130   NVGColor activeNodeColor;
131   /// color of selected wire
132   NVGColor wireSelectColor;
133   /// color of background of node
134   NVGColor nodeBackdropColor;
135 
136   /// how much a noodle curves (0 to 10)
137   int noodleCurving;
138 }
139 
140 /// describes the theme used to draw widgets
141 public struct BNDtheme {
142   /// theme name
143   string name;
144   /// the background color of panels and windows
145   NVGColor backgroundColor;
146   /// theme for labels
147   BNDwidgetTheme regularTheme;
148   /// theme for tool buttons
149   BNDwidgetTheme toolTheme;
150   /// theme for radio buttons
151   BNDwidgetTheme radioTheme;
152   /// theme for text fields
153   BNDwidgetTheme textFieldTheme;
154   /// theme for option buttons (checkboxes)
155   BNDwidgetTheme optionTheme;
156   /// theme for choice buttons (comboboxes)
157   /// Blender calls them "menu buttons"
158   BNDwidgetTheme choiceTheme;
159   /// theme for number fields
160   BNDwidgetTheme numberFieldTheme;
161   /// theme for slider controls
162   BNDwidgetTheme sliderTheme;
163   /// theme for scrollbars
164   BNDwidgetTheme scrollBarTheme;
165   /// theme for tooltips
166   BNDwidgetTheme tooltipTheme;
167   /// theme for menu backgrounds
168   BNDwidgetTheme menuTheme;
169   /// theme for menu items
170   BNDwidgetTheme menuItemTheme;
171   /// theme for nodes
172   BNDnodeTheme nodeTheme;
173 }
174 
175 /// how text on a control is aligned
176 public alias BNDtextAlignment = int;
177 /// how text on a control is aligned (values)
178 public enum /*BNDtextAlignment*/ : int {
179   BND_LEFT = 0, /// left
180   BND_CENTER, /// center
181   BND_RIGHT, /// right
182 }
183 
184 /// states altering the styling of a widget
185 public alias BNDwidgetState = int;
186 /// states altering the styling of a widget (values)
187 public enum /*BNDwidgetState*/ : int {
188   /// not interacting
189   BND_DEFAULT = 0,
190   /// the mouse is hovering over the control
191   BND_HOVER,
192   /// the widget is activated (pressed) or in an active state (toggled)
193   BND_ACTIVE,
194 }
195 
196 /// flags indicating which corners are sharp (for grouping widgets)
197 public alias BNDcornerFlags = int;
198 public enum /*BNDcornerFlags*/ : int {
199   /// all corners are round
200   BND_CORNER_NONE = 0,
201   /// sharp top left corner
202   BND_CORNER_TOP_LEFT = 1,
203   /// sharp top right corner
204   BND_CORNER_TOP_RIGHT = 2,
205   /// sharp bottom right corner
206   BND_CORNER_DOWN_RIGHT = 4,
207   /// sharp bottom left corner
208   BND_CORNER_DOWN_LEFT = 8,
209   /// all corners are sharp; you can invert a set of flags using ^= BND_CORNER_ALL
210   BND_CORNER_ALL = 0xF,
211   /// top border is sharp
212   BND_CORNER_TOP = 3,
213   /// bottom border is sharp
214   BND_CORNER_DOWN = 0xC,
215   /// left border is sharp
216   BND_CORNER_LEFT = 9,
217   /// right border is sharp
218   BND_CORNER_RIGHT = 6,
219 }
220 
221 /** build an icon ID from two coordinates into the icon sheet, where
222  * (0, 0) designates the upper-leftmost icon, (1, 0) the one right next to it,
223  * and so on. */
224 public enum BND_ICONID(int x, int y) = ((x)|((y)<<8));
225 
226 /// alpha of disabled widget groups; can be used in conjunction with nvgGlobalAlpha()
227 public __gshared float BND_DISABLED_ALPHA = 0.5;
228 
229 public __gshared {
230   /// default widget height
231   int BND_WIDGET_HEIGHT = 21;
232   /// default toolbutton width (if icon only)
233   int BND_TOOL_WIDTH = 20;
234 
235   /// default radius of node ports
236   int BND_NODE_PORT_RADIUS = 5;
237   /// top margin of node content
238   int BND_NODE_MARGIN_TOP = 25;
239   /// bottom margin of node content
240   int BND_NODE_MARGIN_DOWN = 5;
241   /// left and right margin of node content
242   int BND_NODE_MARGIN_SIDE = 10;
243   /// height of node title bar
244   int BND_NODE_TITLE_HEIGHT = 20;
245   /// width of node title arrow click area
246   int BND_NODE_ARROW_AREA_WIDTH = 20;
247 
248   /// size of splitter corner click area
249   int BND_SPLITTER_AREA_SIZE = 12;
250 
251   /// width of vertical scrollbar
252   int BND_SCROLLBAR_WIDTH = 13;
253   /// height of horizontal scrollbar
254   int BND_SCROLLBAR_HEIGHT = 14;
255 
256   /// default vertical spacing
257   int BND_VSPACING = 1;
258   /// default vertical spacing between groups
259   int BND_VSPACING_GROUP = 8;
260   /// default horizontal spacing
261   int BND_HSPACING = 8;
262 }
263 
264 public alias BNDicon = int;
265 public enum /*BNDicon*/ {
266   BND_ICON_NONE = BND_ICONID!(0, 29),
267   BND_ICON_QUESTION = BND_ICONID!(1, 29),
268   BND_ICON_ERROR = BND_ICONID!(2, 29),
269   BND_ICON_CANCEL = BND_ICONID!(3, 29),
270   BND_ICON_TRIA_RIGHT = BND_ICONID!(4, 29),
271   BND_ICON_TRIA_DOWN = BND_ICONID!(5, 29),
272   BND_ICON_TRIA_LEFT = BND_ICONID!(6, 29),
273   BND_ICON_TRIA_UP = BND_ICONID!(7, 29),
274   BND_ICON_ARROW_LEFTRIGHT = BND_ICONID!(8, 29),
275   BND_ICON_PLUS = BND_ICONID!(9, 29),
276   BND_ICON_DISCLOSURE_TRI_DOWN = BND_ICONID!(10, 29),
277   BND_ICON_DISCLOSURE_TRI_RIGHT = BND_ICONID!(11, 29),
278   BND_ICON_RADIOBUT_OFF = BND_ICONID!(12, 29),
279   BND_ICON_RADIOBUT_ON = BND_ICONID!(13, 29),
280   BND_ICON_MENU_PANEL = BND_ICONID!(14, 29),
281   BND_ICON_BLENDER = BND_ICONID!(15, 29),
282   BND_ICON_GRIP = BND_ICONID!(16, 29),
283   BND_ICON_DOT = BND_ICONID!(17, 29),
284   BND_ICON_COLLAPSEMENU = BND_ICONID!(18, 29),
285   BND_ICON_X = BND_ICONID!(19, 29),
286   BND_ICON_GO_LEFT = BND_ICONID!(21, 29),
287   BND_ICON_PLUG = BND_ICONID!(22, 29),
288   BND_ICON_UI = BND_ICONID!(23, 29),
289   BND_ICON_NODE = BND_ICONID!(24, 29),
290   BND_ICON_NODE_SEL = BND_ICONID!(25, 29),
291 }
292 public enum /*BNDicon*/ {
293   BND_ICON_FULLSCREEN = BND_ICONID!(0, 28),
294   BND_ICON_SPLITSCREEN = BND_ICONID!(1, 28),
295   BND_ICON_RIGHTARROW_THIN = BND_ICONID!(2, 28),
296   BND_ICON_BORDERMOVE = BND_ICONID!(3, 28),
297   BND_ICON_VIEWZOOM = BND_ICONID!(4, 28),
298   BND_ICON_ZOOMIN = BND_ICONID!(5, 28),
299   BND_ICON_ZOOMOUT = BND_ICONID!(6, 28),
300   BND_ICON_PANEL_CLOSE = BND_ICONID!(7, 28),
301   BND_ICON_COPY_ID = BND_ICONID!(8, 28),
302   BND_ICON_EYEDROPPER = BND_ICONID!(9, 28),
303   BND_ICON_LINK_AREA = BND_ICONID!(10, 28),
304   BND_ICON_AUTO = BND_ICONID!(11, 28),
305   BND_ICON_CHECKBOX_DEHLT = BND_ICONID!(12, 28),
306   BND_ICON_CHECKBOX_HLT = BND_ICONID!(13, 28),
307   BND_ICON_UNLOCKED = BND_ICONID!(14, 28),
308   BND_ICON_LOCKED = BND_ICONID!(15, 28),
309   BND_ICON_UNPINNED = BND_ICONID!(16, 28),
310   BND_ICON_PINNED = BND_ICONID!(17, 28),
311   BND_ICON_SCREEN_BACK = BND_ICONID!(18, 28),
312   BND_ICON_RIGHTARROW = BND_ICONID!(19, 28),
313   BND_ICON_DOWNARROW_HLT = BND_ICONID!(20, 28),
314   BND_ICON_DOTSUP = BND_ICONID!(21, 28),
315   BND_ICON_DOTSDOWN = BND_ICONID!(22, 28),
316   BND_ICON_LINK = BND_ICONID!(23, 28),
317   BND_ICON_INLINK = BND_ICONID!(24, 28),
318   BND_ICON_PLUGIN = BND_ICONID!(25, 28),
319 }
320 public enum /*BNDicon*/ {
321   BND_ICON_HELP = BND_ICONID!(0, 27),
322   BND_ICON_GHOST_ENABLED = BND_ICONID!(1, 27),
323   BND_ICON_COLOR = BND_ICONID!(2, 27),
324   BND_ICON_LINKED = BND_ICONID!(3, 27),
325   BND_ICON_UNLINKED = BND_ICONID!(4, 27),
326   BND_ICON_HAND = BND_ICONID!(5, 27),
327   BND_ICON_ZOOM_ALL = BND_ICONID!(6, 27),
328   BND_ICON_ZOOM_SELECTED = BND_ICONID!(7, 27),
329   BND_ICON_ZOOM_PREVIOUS = BND_ICONID!(8, 27),
330   BND_ICON_ZOOM_IN = BND_ICONID!(9, 27),
331   BND_ICON_ZOOM_OUT = BND_ICONID!(10, 27),
332   BND_ICON_RENDER_REGION = BND_ICONID!(11, 27),
333   BND_ICON_BORDER_RECT = BND_ICONID!(12, 27),
334   BND_ICON_BORDER_LASSO = BND_ICONID!(13, 27),
335   BND_ICON_FREEZE = BND_ICONID!(14, 27),
336   BND_ICON_STYLUS_PRESSURE = BND_ICONID!(15, 27),
337   BND_ICON_GHOST_DISABLED = BND_ICONID!(16, 27),
338   BND_ICON_NEW = BND_ICONID!(17, 27),
339   BND_ICON_FILE_TICK = BND_ICONID!(18, 27),
340   BND_ICON_QUIT = BND_ICONID!(19, 27),
341   BND_ICON_URL = BND_ICONID!(20, 27),
342   BND_ICON_RECOVER_LAST = BND_ICONID!(21, 27),
343   BND_ICON_FULLSCREEN_ENTER = BND_ICONID!(23, 27),
344   BND_ICON_FULLSCREEN_EXIT = BND_ICONID!(24, 27),
345   BND_ICON_BLANK1 = BND_ICONID!(25, 27),
346 }
347 public enum /*BNDicon*/ {
348   BND_ICON_LAMP = BND_ICONID!(0, 26),
349   BND_ICON_MATERIAL = BND_ICONID!(1, 26),
350   BND_ICON_TEXTURE = BND_ICONID!(2, 26),
351   BND_ICON_ANIM = BND_ICONID!(3, 26),
352   BND_ICON_WORLD = BND_ICONID!(4, 26),
353   BND_ICON_SCENE = BND_ICONID!(5, 26),
354   BND_ICON_EDIT = BND_ICONID!(6, 26),
355   BND_ICON_GAME = BND_ICONID!(7, 26),
356   BND_ICON_RADIO = BND_ICONID!(8, 26),
357   BND_ICON_SCRIPT = BND_ICONID!(9, 26),
358   BND_ICON_PARTICLES = BND_ICONID!(10, 26),
359   BND_ICON_PHYSICS = BND_ICONID!(11, 26),
360   BND_ICON_SPEAKER = BND_ICONID!(12, 26),
361   BND_ICON_TEXTURE_SHADED = BND_ICONID!(13, 26),
362 }
363 public enum /*BNDicon*/ {
364   BND_ICON_VIEW3D = BND_ICONID!(0, 25),
365   BND_ICON_IPO = BND_ICONID!(1, 25),
366   BND_ICON_OOPS = BND_ICONID!(2, 25),
367   BND_ICON_BUTS = BND_ICONID!(3, 25),
368   BND_ICON_FILESEL = BND_ICONID!(4, 25),
369   BND_ICON_IMAGE_COL = BND_ICONID!(5, 25),
370   BND_ICON_INFO = BND_ICONID!(6, 25),
371   BND_ICON_SEQUENCE = BND_ICONID!(7, 25),
372   BND_ICON_TEXT = BND_ICONID!(8, 25),
373   BND_ICON_IMASEL = BND_ICONID!(9, 25),
374   BND_ICON_SOUND = BND_ICONID!(10, 25),
375   BND_ICON_ACTION = BND_ICONID!(11, 25),
376   BND_ICON_NLA = BND_ICONID!(12, 25),
377   BND_ICON_SCRIPTWIN = BND_ICONID!(13, 25),
378   BND_ICON_TIME = BND_ICONID!(14, 25),
379   BND_ICON_NODETREE = BND_ICONID!(15, 25),
380   BND_ICON_LOGIC = BND_ICONID!(16, 25),
381   BND_ICON_CONSOLE = BND_ICONID!(17, 25),
382   BND_ICON_PREFERENCES = BND_ICONID!(18, 25),
383   BND_ICON_CLIP = BND_ICONID!(19, 25),
384   BND_ICON_ASSET_MANAGER = BND_ICONID!(20, 25),
385 }
386 public enum /*BNDicon*/ {
387   BND_ICON_OBJECT_DATAMODE = BND_ICONID!(0, 24),
388   BND_ICON_EDITMODE_HLT = BND_ICONID!(1, 24),
389   BND_ICON_FACESEL_HLT = BND_ICONID!(2, 24),
390   BND_ICON_VPAINT_HLT = BND_ICONID!(3, 24),
391   BND_ICON_TPAINT_HLT = BND_ICONID!(4, 24),
392   BND_ICON_WPAINT_HLT = BND_ICONID!(5, 24),
393   BND_ICON_SCULPTMODE_HLT = BND_ICONID!(6, 24),
394   BND_ICON_POSE_HLT = BND_ICONID!(7, 24),
395   BND_ICON_PARTICLEMODE = BND_ICONID!(8, 24),
396   BND_ICON_LIGHTPAINT = BND_ICONID!(9, 24),
397 }
398 public enum /*BNDicon*/ {
399   BND_ICON_SCENE_DATA = BND_ICONID!(0, 23),
400   BND_ICON_RENDERLAYERS = BND_ICONID!(1, 23),
401   BND_ICON_WORLD_DATA = BND_ICONID!(2, 23),
402   BND_ICON_OBJECT_DATA = BND_ICONID!(3, 23),
403   BND_ICON_MESH_DATA = BND_ICONID!(4, 23),
404   BND_ICON_CURVE_DATA = BND_ICONID!(5, 23),
405   BND_ICON_META_DATA = BND_ICONID!(6, 23),
406   BND_ICON_LATTICE_DATA = BND_ICONID!(7, 23),
407   BND_ICON_LAMP_DATA = BND_ICONID!(8, 23),
408   BND_ICON_MATERIAL_DATA = BND_ICONID!(9, 23),
409   BND_ICON_TEXTURE_DATA = BND_ICONID!(10, 23),
410   BND_ICON_ANIM_DATA = BND_ICONID!(11, 23),
411   BND_ICON_CAMERA_DATA = BND_ICONID!(12, 23),
412   BND_ICON_PARTICLE_DATA = BND_ICONID!(13, 23),
413   BND_ICON_LIBRARY_DATA_DIRECT = BND_ICONID!(14, 23),
414   BND_ICON_GROUP = BND_ICONID!(15, 23),
415   BND_ICON_ARMATURE_DATA = BND_ICONID!(16, 23),
416   BND_ICON_POSE_DATA = BND_ICONID!(17, 23),
417   BND_ICON_BONE_DATA = BND_ICONID!(18, 23),
418   BND_ICON_CONSTRAINT = BND_ICONID!(19, 23),
419   BND_ICON_SHAPEKEY_DATA = BND_ICONID!(20, 23),
420   BND_ICON_CONSTRAINT_BONE = BND_ICONID!(21, 23),
421   BND_ICON_CAMERA_STEREO = BND_ICONID!(22, 23),
422   BND_ICON_PACKAGE = BND_ICONID!(23, 23),
423   BND_ICON_UGLYPACKAGE = BND_ICONID!(24, 23),
424 }
425 public enum /*BNDicon*/ {
426   BND_ICON_BRUSH_DATA = BND_ICONID!(0, 22),
427   BND_ICON_IMAGE_DATA = BND_ICONID!(1, 22),
428   BND_ICON_FILE = BND_ICONID!(2, 22),
429   BND_ICON_FCURVE = BND_ICONID!(3, 22),
430   BND_ICON_FONT_DATA = BND_ICONID!(4, 22),
431   BND_ICON_RENDER_RESULT = BND_ICONID!(5, 22),
432   BND_ICON_SURFACE_DATA = BND_ICONID!(6, 22),
433   BND_ICON_EMPTY_DATA = BND_ICONID!(7, 22),
434   BND_ICON_SETTINGS = BND_ICONID!(8, 22),
435   BND_ICON_RENDER_ANIMATION = BND_ICONID!(9, 22),
436   BND_ICON_RENDER_STILL = BND_ICONID!(10, 22),
437   BND_ICON_BOIDS = BND_ICONID!(12, 22),
438   BND_ICON_STRANDS = BND_ICONID!(13, 22),
439   BND_ICON_LIBRARY_DATA_INDIRECT = BND_ICONID!(14, 22),
440   BND_ICON_GREASEPENCIL = BND_ICONID!(15, 22),
441   BND_ICON_LINE_DATA = BND_ICONID!(16, 22),
442   BND_ICON_GROUP_BONE = BND_ICONID!(18, 22),
443   BND_ICON_GROUP_VERTEX = BND_ICONID!(19, 22),
444   BND_ICON_GROUP_VCOL = BND_ICONID!(20, 22),
445   BND_ICON_GROUP_UVS = BND_ICONID!(21, 22),
446   BND_ICON_RNA = BND_ICONID!(24, 22),
447   BND_ICON_RNA_ADD = BND_ICONID!(25, 22),
448 }
449 public enum /*BNDicon*/ {
450   BND_ICON_OUTLINER_OB_EMPTY = BND_ICONID!(0, 20),
451   BND_ICON_OUTLINER_OB_MESH = BND_ICONID!(1, 20),
452   BND_ICON_OUTLINER_OB_CURVE = BND_ICONID!(2, 20),
453   BND_ICON_OUTLINER_OB_LATTICE = BND_ICONID!(3, 20),
454   BND_ICON_OUTLINER_OB_META = BND_ICONID!(4, 20),
455   BND_ICON_OUTLINER_OB_LAMP = BND_ICONID!(5, 20),
456   BND_ICON_OUTLINER_OB_CAMERA = BND_ICONID!(6, 20),
457   BND_ICON_OUTLINER_OB_ARMATURE = BND_ICONID!(7, 20),
458   BND_ICON_OUTLINER_OB_FONT = BND_ICONID!(8, 20),
459   BND_ICON_OUTLINER_OB_SURFACE = BND_ICONID!(9, 20),
460   BND_ICON_OUTLINER_OB_SPEAKER = BND_ICONID!(10, 20),
461   BND_ICON_RESTRICT_VIEW_OFF = BND_ICONID!(19, 20),
462   BND_ICON_RESTRICT_VIEW_ON = BND_ICONID!(20, 20),
463   BND_ICON_RESTRICT_SELECT_OFF = BND_ICONID!(21, 20),
464   BND_ICON_RESTRICT_SELECT_ON = BND_ICONID!(22, 20),
465   BND_ICON_RESTRICT_RENDER_OFF = BND_ICONID!(23, 20),
466   BND_ICON_RESTRICT_RENDER_ON = BND_ICONID!(24, 20),
467 }
468 public enum /*BNDicon*/ {
469   BND_ICON_OUTLINER_DATA_EMPTY = BND_ICONID!(0, 19),
470   BND_ICON_OUTLINER_DATA_MESH = BND_ICONID!(1, 19),
471   BND_ICON_OUTLINER_DATA_CURVE = BND_ICONID!(2, 19),
472   BND_ICON_OUTLINER_DATA_LATTICE = BND_ICONID!(3, 19),
473   BND_ICON_OUTLINER_DATA_META = BND_ICONID!(4, 19),
474   BND_ICON_OUTLINER_DATA_LAMP = BND_ICONID!(5, 19),
475   BND_ICON_OUTLINER_DATA_CAMERA = BND_ICONID!(6, 19),
476   BND_ICON_OUTLINER_DATA_ARMATURE = BND_ICONID!(7, 19),
477   BND_ICON_OUTLINER_DATA_FONT = BND_ICONID!(8, 19),
478   BND_ICON_OUTLINER_DATA_SURFACE = BND_ICONID!(9, 19),
479   BND_ICON_OUTLINER_DATA_SPEAKER = BND_ICONID!(10, 19),
480   BND_ICON_OUTLINER_DATA_POSE = BND_ICONID!(11, 19),
481 }
482 public enum /*BNDicon*/ {
483   BND_ICON_MESH_PLANE = BND_ICONID!(0, 18),
484   BND_ICON_MESH_CUBE = BND_ICONID!(1, 18),
485   BND_ICON_MESH_CIRCLE = BND_ICONID!(2, 18),
486   BND_ICON_MESH_UVSPHERE = BND_ICONID!(3, 18),
487   BND_ICON_MESH_ICOSPHERE = BND_ICONID!(4, 18),
488   BND_ICON_MESH_GRID = BND_ICONID!(5, 18),
489   BND_ICON_MESH_MONKEY = BND_ICONID!(6, 18),
490   BND_ICON_MESH_CYLINDER = BND_ICONID!(7, 18),
491   BND_ICON_MESH_TORUS = BND_ICONID!(8, 18),
492   BND_ICON_MESH_CONE = BND_ICONID!(9, 18),
493   BND_ICON_LAMP_POINT = BND_ICONID!(12, 18),
494   BND_ICON_LAMP_SUN = BND_ICONID!(13, 18),
495   BND_ICON_LAMP_SPOT = BND_ICONID!(14, 18),
496   BND_ICON_LAMP_HEMI = BND_ICONID!(15, 18),
497   BND_ICON_LAMP_AREA = BND_ICONID!(16, 18),
498   BND_ICON_META_EMPTY = BND_ICONID!(19, 18),
499   BND_ICON_META_PLANE = BND_ICONID!(20, 18),
500   BND_ICON_META_CUBE = BND_ICONID!(21, 18),
501   BND_ICON_META_BALL = BND_ICONID!(22, 18),
502   BND_ICON_META_ELLIPSOID = BND_ICONID!(23, 18),
503   BND_ICON_META_CAPSULE = BND_ICONID!(24, 18),
504 }
505 public enum /*BNDicon*/ {
506   BND_ICON_SURFACE_NCURVE = BND_ICONID!(0, 17),
507   BND_ICON_SURFACE_NCIRCLE = BND_ICONID!(1, 17),
508   BND_ICON_SURFACE_NSURFACE = BND_ICONID!(2, 17),
509   BND_ICON_SURFACE_NCYLINDER = BND_ICONID!(3, 17),
510   BND_ICON_SURFACE_NSPHERE = BND_ICONID!(4, 17),
511   BND_ICON_SURFACE_NTORUS = BND_ICONID!(5, 17),
512   BND_ICON_CURVE_BEZCURVE = BND_ICONID!(9, 17),
513   BND_ICON_CURVE_BEZCIRCLE = BND_ICONID!(10, 17),
514   BND_ICON_CURVE_NCURVE = BND_ICONID!(11, 17),
515   BND_ICON_CURVE_NCIRCLE = BND_ICONID!(12, 17),
516   BND_ICON_CURVE_PATH = BND_ICONID!(13, 17),
517   BND_ICON_COLOR_RED = BND_ICONID!(19, 17),
518   BND_ICON_COLOR_GREEN = BND_ICONID!(20, 17),
519   BND_ICON_COLOR_BLUE = BND_ICONID!(21, 17),
520 }
521 public enum /*BNDicon*/ {
522   BND_ICON_FORCE_FORCE = BND_ICONID!(0, 16),
523   BND_ICON_FORCE_WIND = BND_ICONID!(1, 16),
524   BND_ICON_FORCE_VORTEX = BND_ICONID!(2, 16),
525   BND_ICON_FORCE_MAGNETIC = BND_ICONID!(3, 16),
526   BND_ICON_FORCE_HARMONIC = BND_ICONID!(4, 16),
527   BND_ICON_FORCE_CHARGE = BND_ICONID!(5, 16),
528   BND_ICON_FORCE_LENNARDJONES = BND_ICONID!(6, 16),
529   BND_ICON_FORCE_TEXTURE = BND_ICONID!(7, 16),
530   BND_ICON_FORCE_CURVE = BND_ICONID!(8, 16),
531   BND_ICON_FORCE_BOID = BND_ICONID!(9, 16),
532   BND_ICON_FORCE_TURBULENCE = BND_ICONID!(10, 16),
533   BND_ICON_FORCE_DRAG = BND_ICONID!(11, 16),
534   BND_ICON_FORCE_SMOKEFLOW = BND_ICONID!(12, 16),
535 }
536 public enum /*BNDicon*/ {
537   BND_ICON_MODIFIER = BND_ICONID!(0, 12),
538   BND_ICON_MOD_WAVE = BND_ICONID!(1, 12),
539   BND_ICON_MOD_BUILD = BND_ICONID!(2, 12),
540   BND_ICON_MOD_DECIM = BND_ICONID!(3, 12),
541   BND_ICON_MOD_MIRROR = BND_ICONID!(4, 12),
542   BND_ICON_MOD_SOFT = BND_ICONID!(5, 12),
543   BND_ICON_MOD_SUBSURF = BND_ICONID!(6, 12),
544   BND_ICON_HOOK = BND_ICONID!(7, 12),
545   BND_ICON_MOD_PHYSICS = BND_ICONID!(8, 12),
546   BND_ICON_MOD_PARTICLES = BND_ICONID!(9, 12),
547   BND_ICON_MOD_BOOLEAN = BND_ICONID!(10, 12),
548   BND_ICON_MOD_EDGESPLIT = BND_ICONID!(11, 12),
549   BND_ICON_MOD_ARRAY = BND_ICONID!(12, 12),
550   BND_ICON_MOD_UVPROJECT = BND_ICONID!(13, 12),
551   BND_ICON_MOD_DISPLACE = BND_ICONID!(14, 12),
552   BND_ICON_MOD_CURVE = BND_ICONID!(15, 12),
553   BND_ICON_MOD_LATTICE = BND_ICONID!(16, 12),
554   BND_ICON_CONSTRAINT_DATA = BND_ICONID!(17, 12),
555   BND_ICON_MOD_ARMATURE = BND_ICONID!(18, 12),
556   BND_ICON_MOD_SHRINKWRAP = BND_ICONID!(19, 12),
557   BND_ICON_MOD_CAST = BND_ICONID!(20, 12),
558   BND_ICON_MOD_MESHDEFORM = BND_ICONID!(21, 12),
559   BND_ICON_MOD_BEVEL = BND_ICONID!(22, 12),
560   BND_ICON_MOD_SMOOTH = BND_ICONID!(23, 12),
561   BND_ICON_MOD_SIMPLEDEFORM = BND_ICONID!(24, 12),
562   BND_ICON_MOD_MASK = BND_ICONID!(25, 12),
563 }
564 public enum /*BNDicon*/ {
565   BND_ICON_MOD_CLOTH = BND_ICONID!(0, 11),
566   BND_ICON_MOD_EXPLODE = BND_ICONID!(1, 11),
567   BND_ICON_MOD_FLUIDSIM = BND_ICONID!(2, 11),
568   BND_ICON_MOD_MULTIRES = BND_ICONID!(3, 11),
569   BND_ICON_MOD_SMOKE = BND_ICONID!(4, 11),
570   BND_ICON_MOD_SOLIDIFY = BND_ICONID!(5, 11),
571   BND_ICON_MOD_SCREW = BND_ICONID!(6, 11),
572   BND_ICON_MOD_VERTEX_WEIGHT = BND_ICONID!(7, 11),
573   BND_ICON_MOD_DYNAMICPAINT = BND_ICONID!(8, 11),
574   BND_ICON_MOD_REMESH = BND_ICONID!(9, 11),
575   BND_ICON_MOD_OCEAN = BND_ICONID!(10, 11),
576   BND_ICON_MOD_WARP = BND_ICONID!(11, 11),
577   BND_ICON_MOD_SKIN = BND_ICONID!(12, 11),
578   BND_ICON_MOD_TRIANGULATE = BND_ICONID!(13, 11),
579   BND_ICON_MOD_WIREFRAME = BND_ICONID!(14, 11),
580 }
581 public enum /*BNDicon*/ {
582   BND_ICON_REC = BND_ICONID!(0, 10),
583   BND_ICON_PLAY = BND_ICONID!(1, 10),
584   BND_ICON_FF = BND_ICONID!(2, 10),
585   BND_ICON_REW = BND_ICONID!(3, 10),
586   BND_ICON_PAUSE = BND_ICONID!(4, 10),
587   BND_ICON_PREV_KEYFRAME = BND_ICONID!(5, 10),
588   BND_ICON_NEXT_KEYFRAME = BND_ICONID!(6, 10),
589   BND_ICON_PLAY_AUDIO = BND_ICONID!(7, 10),
590   BND_ICON_PLAY_REVERSE = BND_ICONID!(8, 10),
591   BND_ICON_PREVIEW_RANGE = BND_ICONID!(9, 10),
592   BND_ICON_ACTION_TWEAK = BND_ICONID!(10, 10),
593   BND_ICON_PMARKER_ACT = BND_ICONID!(11, 10),
594   BND_ICON_PMARKER_SEL = BND_ICONID!(12, 10),
595   BND_ICON_PMARKER = BND_ICONID!(13, 10),
596   BND_ICON_MARKER_HLT = BND_ICONID!(14, 10),
597   BND_ICON_MARKER = BND_ICONID!(15, 10),
598   BND_ICON_SPACE2 = BND_ICONID!(16, 10),
599   BND_ICON_SPACE3 = BND_ICONID!(17, 10),
600   BND_ICON_KEYINGSET = BND_ICONID!(18, 10),
601   BND_ICON_KEY_DEHLT = BND_ICONID!(19, 10),
602   BND_ICON_KEY_HLT = BND_ICONID!(20, 10),
603   BND_ICON_MUTE_IPO_OFF = BND_ICONID!(21, 10),
604   BND_ICON_MUTE_IPO_ON = BND_ICONID!(22, 10),
605   BND_ICON_VISIBLE_IPO_OFF = BND_ICONID!(23, 10),
606   BND_ICON_VISIBLE_IPO_ON = BND_ICONID!(24, 10),
607   BND_ICON_DRIVER = BND_ICONID!(25, 10),
608 }
609 public enum /*BNDicon*/ {
610   BND_ICON_SOLO_OFF = BND_ICONID!(0, 9),
611   BND_ICON_SOLO_ON = BND_ICONID!(1, 9),
612   BND_ICON_FRAME_PREV = BND_ICONID!(2, 9),
613   BND_ICON_FRAME_NEXT = BND_ICONID!(3, 9),
614   BND_ICON_NLA_PUSHDOWN = BND_ICONID!(4, 9),
615   BND_ICON_IPO_CONSTANT = BND_ICONID!(5, 9),
616   BND_ICON_IPO_LINEAR = BND_ICONID!(6, 9),
617   BND_ICON_IPO_BEZIER = BND_ICONID!(7, 9),
618   BND_ICON_IPO_SINE = BND_ICONID!(8, 9),
619   BND_ICON_IPO_QUAD = BND_ICONID!(9, 9),
620   BND_ICON_IPO_CUBIC = BND_ICONID!(10, 9),
621   BND_ICON_IPO_QUART = BND_ICONID!(11, 9),
622   BND_ICON_IPO_QUINT = BND_ICONID!(12, 9),
623   BND_ICON_IPO_EXPO = BND_ICONID!(13, 9),
624   BND_ICON_IPO_CIRC = BND_ICONID!(14, 9),
625   BND_ICON_IPO_BOUNCE = BND_ICONID!(15, 9),
626   BND_ICON_IPO_ELASTIC = BND_ICONID!(16, 9),
627   BND_ICON_IPO_BACK = BND_ICONID!(17, 9),
628   BND_ICON_IPO_EASE_IN = BND_ICONID!(18, 9),
629   BND_ICON_IPO_EASE_OUT = BND_ICONID!(19, 9),
630   BND_ICON_IPO_EASE_IN_OUT = BND_ICONID!(20, 9),
631 }
632 public enum /*BNDicon*/ {
633   BND_ICON_VERTEXSEL = BND_ICONID!(0, 8),
634   BND_ICON_EDGESEL = BND_ICONID!(1, 8),
635   BND_ICON_FACESEL = BND_ICONID!(2, 8),
636   BND_ICON_LOOPSEL = BND_ICONID!(3, 8),
637   BND_ICON_ROTATE = BND_ICONID!(5, 8),
638   BND_ICON_CURSOR = BND_ICONID!(6, 8),
639   BND_ICON_ROTATECOLLECTION = BND_ICONID!(7, 8),
640   BND_ICON_ROTATECENTER = BND_ICONID!(8, 8),
641   BND_ICON_ROTACTIVE = BND_ICONID!(9, 8),
642   BND_ICON_ALIGN = BND_ICONID!(10, 8),
643   BND_ICON_SMOOTHCURVE = BND_ICONID!(12, 8),
644   BND_ICON_SPHERECURVE = BND_ICONID!(13, 8),
645   BND_ICON_ROOTCURVE = BND_ICONID!(14, 8),
646   BND_ICON_SHARPCURVE = BND_ICONID!(15, 8),
647   BND_ICON_LINCURVE = BND_ICONID!(16, 8),
648   BND_ICON_NOCURVE = BND_ICONID!(17, 8),
649   BND_ICON_RNDCURVE = BND_ICONID!(18, 8),
650   BND_ICON_PROP_OFF = BND_ICONID!(19, 8),
651   BND_ICON_PROP_ON = BND_ICONID!(20, 8),
652   BND_ICON_PROP_CON = BND_ICONID!(21, 8),
653   BND_ICON_SCULPT_DYNTOPO = BND_ICONID!(22, 8),
654   BND_ICON_PARTICLE_POINT = BND_ICONID!(23, 8),
655   BND_ICON_PARTICLE_TIP = BND_ICONID!(24, 8),
656   BND_ICON_PARTICLE_PATH = BND_ICONID!(25, 8),
657 }
658 public enum /*BNDicon*/ {
659   BND_ICON_MAN_TRANS = BND_ICONID!(0, 7),
660   BND_ICON_MAN_ROT = BND_ICONID!(1, 7),
661   BND_ICON_MAN_SCALE = BND_ICONID!(2, 7),
662   BND_ICON_MANIPUL = BND_ICONID!(3, 7),
663   BND_ICON_SNAP_OFF = BND_ICONID!(4, 7),
664   BND_ICON_SNAP_ON = BND_ICONID!(5, 7),
665   BND_ICON_SNAP_NORMAL = BND_ICONID!(6, 7),
666   BND_ICON_SNAP_INCREMENT = BND_ICONID!(7, 7),
667   BND_ICON_SNAP_VERTEX = BND_ICONID!(8, 7),
668   BND_ICON_SNAP_EDGE = BND_ICONID!(9, 7),
669   BND_ICON_SNAP_FACE = BND_ICONID!(10, 7),
670   BND_ICON_SNAP_VOLUME = BND_ICONID!(11, 7),
671   BND_ICON_STICKY_UVS_LOC = BND_ICONID!(13, 7),
672   BND_ICON_STICKY_UVS_DISABLE = BND_ICONID!(14, 7),
673   BND_ICON_STICKY_UVS_VERT = BND_ICONID!(15, 7),
674   BND_ICON_CLIPUV_DEHLT = BND_ICONID!(16, 7),
675   BND_ICON_CLIPUV_HLT = BND_ICONID!(17, 7),
676   BND_ICON_SNAP_PEEL_OBJECT = BND_ICONID!(18, 7),
677   BND_ICON_GRID = BND_ICONID!(19, 7),
678 }
679 public enum /*BNDicon*/ {
680   BND_ICON_PASTEDOWN = BND_ICONID!(0, 6),
681   BND_ICON_COPYDOWN = BND_ICONID!(1, 6),
682   BND_ICON_PASTEFLIPUP = BND_ICONID!(2, 6),
683   BND_ICON_PASTEFLIPDOWN = BND_ICONID!(3, 6),
684   BND_ICON_SNAP_SURFACE = BND_ICONID!(8, 6),
685   BND_ICON_AUTOMERGE_ON = BND_ICONID!(9, 6),
686   BND_ICON_AUTOMERGE_OFF = BND_ICONID!(10, 6),
687   BND_ICON_RETOPO = BND_ICONID!(11, 6),
688   BND_ICON_UV_VERTEXSEL = BND_ICONID!(12, 6),
689   BND_ICON_UV_EDGESEL = BND_ICONID!(13, 6),
690   BND_ICON_UV_FACESEL = BND_ICONID!(14, 6),
691   BND_ICON_UV_ISLANDSEL = BND_ICONID!(15, 6),
692   BND_ICON_UV_SYNC_SELECT = BND_ICONID!(16, 6),
693 }
694 public enum /*BNDicon*/ {
695   BND_ICON_BBOX = BND_ICONID!(0, 5),
696   BND_ICON_WIRE = BND_ICONID!(1, 5),
697   BND_ICON_SOLID = BND_ICONID!(2, 5),
698   BND_ICON_SMOOTH = BND_ICONID!(3, 5),
699   BND_ICON_POTATO = BND_ICONID!(4, 5),
700   BND_ICON_ORTHO = BND_ICONID!(6, 5),
701   BND_ICON_LOCKVIEW_OFF = BND_ICONID!(9, 5),
702   BND_ICON_LOCKVIEW_ON = BND_ICONID!(10, 5),
703   BND_ICON_AXIS_SIDE = BND_ICONID!(12, 5),
704   BND_ICON_AXIS_FRONT = BND_ICONID!(13, 5),
705   BND_ICON_AXIS_TOP = BND_ICONID!(14, 5),
706   BND_ICON_NDOF_DOM = BND_ICONID!(15, 5),
707   BND_ICON_NDOF_TURN = BND_ICONID!(16, 5),
708   BND_ICON_NDOF_FLY = BND_ICONID!(17, 5),
709   BND_ICON_NDOF_TRANS = BND_ICONID!(18, 5),
710   BND_ICON_LAYER_USED = BND_ICONID!(19, 5),
711   BND_ICON_LAYER_ACTIVE = BND_ICONID!(20, 5),
712 }
713 public enum /*BNDicon*/ {
714   BND_ICON_SORTALPHA = BND_ICONID!(0, 3),
715   BND_ICON_SORTBYEXT = BND_ICONID!(1, 3),
716   BND_ICON_SORTTIME = BND_ICONID!(2, 3),
717   BND_ICON_SORTSIZE = BND_ICONID!(3, 3),
718   BND_ICON_LONGDISPLAY = BND_ICONID!(4, 3),
719   BND_ICON_SHORTDISPLAY = BND_ICONID!(5, 3),
720   BND_ICON_GHOST = BND_ICONID!(6, 3),
721   BND_ICON_IMGDISPLAY = BND_ICONID!(7, 3),
722   BND_ICON_SAVE_AS = BND_ICONID!(8, 3),
723   BND_ICON_SAVE_COPY = BND_ICONID!(9, 3),
724   BND_ICON_BOOKMARKS = BND_ICONID!(10, 3),
725   BND_ICON_FONTPREVIEW = BND_ICONID!(11, 3),
726   BND_ICON_FILTER = BND_ICONID!(12, 3),
727   BND_ICON_NEWFOLDER = BND_ICONID!(13, 3),
728   BND_ICON_OPEN_RECENT = BND_ICONID!(14, 3),
729   BND_ICON_FILE_PARENT = BND_ICONID!(15, 3),
730   BND_ICON_FILE_REFRESH = BND_ICONID!(16, 3),
731   BND_ICON_FILE_FOLDER = BND_ICONID!(17, 3),
732   BND_ICON_FILE_BLANK = BND_ICONID!(18, 3),
733   BND_ICON_FILE_BLEND = BND_ICONID!(19, 3),
734   BND_ICON_FILE_IMAGE = BND_ICONID!(20, 3),
735   BND_ICON_FILE_MOVIE = BND_ICONID!(21, 3),
736   BND_ICON_FILE_SCRIPT = BND_ICONID!(22, 3),
737   BND_ICON_FILE_SOUND = BND_ICONID!(23, 3),
738   BND_ICON_FILE_FONT = BND_ICONID!(24, 3),
739   BND_ICON_FILE_TEXT = BND_ICONID!(25, 3),
740 }
741 public enum /*BNDicon*/ {
742   BND_ICON_RECOVER_AUTO = BND_ICONID!(0, 2),
743   BND_ICON_SAVE_PREFS = BND_ICONID!(1, 2),
744   BND_ICON_LINK_BLEND = BND_ICONID!(2, 2),
745   BND_ICON_APPEND_BLEND = BND_ICONID!(3, 2),
746   BND_ICON_IMPORT = BND_ICONID!(4, 2),
747   BND_ICON_EXPORT = BND_ICONID!(5, 2),
748   BND_ICON_EXTERNAL_DATA = BND_ICONID!(6, 2),
749   BND_ICON_LOAD_FACTORY = BND_ICONID!(7, 2),
750   BND_ICON_LOOP_BACK = BND_ICONID!(13, 2),
751   BND_ICON_LOOP_FORWARDS = BND_ICONID!(14, 2),
752   BND_ICON_BACK = BND_ICONID!(15, 2),
753   BND_ICON_FORWARD = BND_ICONID!(16, 2),
754   BND_ICON_FILE_BACKUP = BND_ICONID!(24, 2),
755   BND_ICON_DISK_DRIVE = BND_ICONID!(25, 2),
756 }
757 public enum /*BNDicon*/ {
758   BND_ICON_MATPLANE = BND_ICONID!(0, 1),
759   BND_ICON_MATSPHERE = BND_ICONID!(1, 1),
760   BND_ICON_MATCUBE = BND_ICONID!(2, 1),
761   BND_ICON_MONKEY = BND_ICONID!(3, 1),
762   BND_ICON_HAIR = BND_ICONID!(4, 1),
763   BND_ICON_ALIASED = BND_ICONID!(5, 1),
764   BND_ICON_ANTIALIASED = BND_ICONID!(6, 1),
765   BND_ICON_MAT_SPHERE_SKY = BND_ICONID!(7, 1),
766   BND_ICON_WORDWRAP_OFF = BND_ICONID!(12, 1),
767   BND_ICON_WORDWRAP_ON = BND_ICONID!(13, 1),
768   BND_ICON_SYNTAX_OFF = BND_ICONID!(14, 1),
769   BND_ICON_SYNTAX_ON = BND_ICONID!(15, 1),
770   BND_ICON_LINENUMBERS_OFF = BND_ICONID!(16, 1),
771   BND_ICON_LINENUMBERS_ON = BND_ICONID!(17, 1),
772   BND_ICON_SCRIPTPLUGINS = BND_ICONID!(18, 1),
773 }
774 public enum /*BNDicon*/ {
775   BND_ICON_SEQ_SEQUENCER = BND_ICONID!(0, 0),
776   BND_ICON_SEQ_PREVIEW = BND_ICONID!(1, 0),
777   BND_ICON_SEQ_LUMA_WAVEFORM = BND_ICONID!(2, 0),
778   BND_ICON_SEQ_CHROMA_SCOPE = BND_ICONID!(3, 0),
779   BND_ICON_SEQ_HISTOGRAM = BND_ICONID!(4, 0),
780   BND_ICON_SEQ_SPLITVIEW = BND_ICONID!(5, 0),
781   BND_ICON_IMAGE_RGB = BND_ICONID!(9, 0),
782   BND_ICON_IMAGE_RGB_ALPHA = BND_ICONID!(10, 0),
783   BND_ICON_IMAGE_ALPHA = BND_ICONID!(11, 0),
784   BND_ICON_IMAGE_ZDEPTH = BND_ICONID!(12, 0),
785   BND_ICON_IMAGEFILE = BND_ICONID!(13, 0),
786 }
787 
788 
789 ////////////////////////////////////////////////////////////////////////////////
790 public float bndMin(T) (in T a, in T b) if (__traits(isFloating, T)) { pragma(inline, true); import std.math : isNaN; return (isNaN(a) ? b : ( isNaN(b) ? a : (a < b ? a : b))); }
791 public float bndMax(T) (in T a, in T b) if (__traits(isFloating, T)) { pragma(inline, true); import std.math : isNaN; return (isNaN(a) ? b : ( isNaN(b) ? a : (a > b ? a : b))); }
792 
793 
794 ////////////////////////////////////////////////////////////////////////////////
795 /// default text size
796 public __gshared float BND_LABEL_FONT_SIZE = 13;
797 
798 /// default text padding in inner box
799 public __gshared int BND_PAD_LEFT = 8;
800 public __gshared int BND_PAD_RIGHT = 8;
801 
802 /// label: value separator string
803 public __gshared string BND_LABEL_SEPARATOR = ": ";
804 
805 /// alpha intensity of transparent items (0xa4)
806 public __gshared float BND_TRANSPARENT_ALPHA = 0.643;
807 
808 /// shade intensity of beveled panels
809 public __gshared int BND_BEVEL_SHADE = 30;
810 /// shade intensity of beveled insets
811 public __gshared int BND_INSET_BEVEL_SHADE = 30;
812 /// shade intensity of hovered inner boxes
813 public __gshared int BND_HOVER_SHADE = 15;
814 /// shade intensity of splitter bevels
815 public __gshared int BND_SPLITTER_SHADE = 100;
816 
817 /// width of icon sheet
818 public __gshared int BND_ICON_SHEET_WIDTH = 602;
819 /// height of icon sheet
820 public __gshared int BND_ICON_SHEET_HEIGHT = 640;
821 /// gridsize of icon sheet in both dimensions
822 public __gshared int BND_ICON_SHEET_GRID = 21;
823 /// offset of first icon tile relative to left border
824 public __gshared int BND_ICON_SHEET_OFFSET_X = 5;
825 /// offset of first icon tile relative to top border
826 public __gshared int BND_ICON_SHEET_OFFSET_Y = 10;
827 /// resolution of single icon
828 public __gshared int BND_ICON_SHEET_RES = 16;
829 
830 /// size of number field arrow
831 public __gshared float BND_NUMBER_ARROW_SIZE = 4;
832 
833 /// default text color
834 public enum BND_COLOR_TEXT = nvgRGBAf(0, 0, 0, 1);
835 /// default highlighted text color
836 public enum BND_COLOR_TEXT_SELECTED = nvgRGBAf(1, 1, 1, 1);
837 /// default color for active element
838 public enum BND_COLOR_ACTIVE = nvgRGBA(255, 127, 0, 255);
839 
840 /// radius of tool button
841 public __gshared float BND_TOOL_RADIUS = 4;
842 
843 /// radius of option button
844 public __gshared float BND_OPTION_RADIUS = 4;
845 /// width of option button checkbox
846 public __gshared float BND_OPTION_WIDTH = 14;
847 /// height of option button checkbox
848 public __gshared float BND_OPTION_HEIGHT = 15;
849 
850 /// radius of text field
851 public __gshared float BND_TEXT_RADIUS = 4;
852 
853 /// radius of number button
854 public __gshared float BND_NUMBER_RADIUS = 10;
855 
856 /// radius of menu popup
857 public __gshared float BND_MENU_RADIUS = 3;
858 /// feather of menu popup shadow
859 public __gshared float BND_SHADOW_FEATHER = 12;
860 /// alpha of menu popup shadow
861 public __gshared float BND_SHADOW_ALPHA = 0.5;
862 
863 /// radius of scrollbar
864 public __gshared float BND_SCROLLBAR_RADIUS = 7;
865 /// shade intensity of active scrollbar
866 public __gshared int BND_SCROLLBAR_ACTIVE_SHADE = 15;
867 
868 /// max glyphs for position testing
869 public enum BND_MAX_GLYPHS = 1024;
870 
871 /// max rows for position testing
872 public enum BND_MAX_ROWS = 32;
873 
874 /// text distance from bottom
875 public __gshared int BND_TEXT_PAD_DOWN = 7;
876 
877 /// stroke width of wire outline
878 public __gshared float BND_NODE_WIRE_OUTLINE_WIDTH = 4;
879 /// stroke width of wire
880 public __gshared float BND_NODE_WIRE_WIDTH = 2;
881 /// radius of node box
882 public __gshared float BND_NODE_RADIUS = 8;
883 /// feather of node title text
884 public __gshared float BND_NODE_TITLE_FEATHER = 1;
885 /// size of node title arrow
886 public __gshared float BND_NODE_ARROW_SIZE = 9;
887 
888 
889 ////////////////////////////////////////////////////////////////////////////////
890 public float bndClamp() (float v, float mn, float mx) { pragma(inline, true); return (v > mx ? mx : (v < mn ? mn : v)); }
891 
892 
893 ////////////////////////////////////////////////////////////////////////////////
894 
895 /// the initial theme
896 public __gshared BNDtheme bndTheme = BNDtheme(
897   "default theme",
898   // backgroundColor
899   nvgRGBA(113, 113, 113, 255),
900   // regularTheme
901   BNDwidgetTheme(
902     "regular",
903     nvgRGBA( 24,  24,  24, 255), // outlineColor
904     nvgRGBA( 24,  24,  24, 255), // itemColor
905     nvgRGBA(153, 153, 153, 255), // innerColor
906     nvgRGBA( 99,  99,  99, 255), // innerSelectedColor
907     BND_COLOR_TEXT, // textColor
908     BND_COLOR_TEXT_SELECTED, // textSelectedColor
909     0, // shadeTop
910     0, // shadeDown
911   ),
912   // toolTheme
913   BNDwidgetTheme(
914     "tool",
915     nvgRGBA( 24,  24,  24, 255), // outlineColor
916     nvgRGBA( 24,  24,  24, 255), // itemColor
917     nvgRGBA(153, 153, 153, 255), // innerColor
918     nvgRGBA( 99,  99,  99, 255), // innerSelectedColor
919     BND_COLOR_TEXT, // textColor
920     BND_COLOR_TEXT_SELECTED, // textSelectedColor
921     15, // shadeTop
922     -15, // shadeDown
923   ),
924   // radioTheme
925   BNDwidgetTheme(
926     "radio",
927     nvgRGBA(  0,   0,   0, 255), // outlineColor
928     nvgRGBA(255, 255, 255, 255), // itemColor
929     nvgRGBA( 70,  70,  70, 255), // innerColor
930     BND_COLOR_ACTIVE, // innerSelectedColor
931     BND_COLOR_TEXT_SELECTED, // textColor
932     BND_COLOR_TEXT, // textSelectedColor
933     15, // shadeTop
934     -15, // shadeDown
935   ),
936   // textFieldTheme
937   BNDwidgetTheme(
938     "text field",
939     nvgRGBA( 24,  24,  24, 255), // outlineColor
940     nvgRGBA( 60, 160, 160, 255), // itemColor
941     nvgRGBA(153, 153, 153, 255), // innerColor
942     nvgRGBA(213, 213, 213, 255), // innerSelectedColor
943     BND_COLOR_TEXT, // textColor
944     BND_COLOR_TEXT, // textSelectedColor
945     0, // shadeTop
946     25, // shadeDown
947     NVGColor.transparent, // textHoverColor
948     NVGColor.black, // textCaretColor
949   ),
950   // optionTheme
951   BNDwidgetTheme(
952     "option",
953     nvgRGBA(  0,   0,   0, 255), // outlineColor
954     nvgRGBA(255, 255, 255, 255), // itemColor
955     nvgRGBA( 70,  70,  70, 255), // innerColor
956     nvgRGBA( 70,  70,  70, 255), // innerSelectedColor
957     BND_COLOR_TEXT, // textColor
958     BND_COLOR_TEXT_SELECTED, // textSelectedColor
959     15, // shadeTop
960     -15, // shadeDown
961   ),
962   // choiceTheme
963   BNDwidgetTheme(
964     "choice",
965     nvgRGBA(  0,   0,   0, 255), // outlineColor
966     nvgRGBA(255, 255, 255, 255), // itemColor
967     nvgRGBA( 70,  70,  70, 255), // innerColor
968     nvgRGBA( 70,  70,  70, 255), // innerSelectedColor
969     BND_COLOR_TEXT_SELECTED, // textColor
970     nvgRGBA(204, 204, 204, 255), // textSelectedColor
971     15, // shadeTop
972     -15, // shadeDown
973   ),
974   // numberFieldTheme
975   BNDwidgetTheme(
976     "number field",
977     nvgRGBA( 24,  24,  24, 255), // outlineColor
978     nvgRGBA( 90,  90,  90, 255), // itemColor
979     nvgRGBA(180, 180, 180, 255), // innerColor
980     nvgRGBA(153, 153, 153, 255), // innerSelectedColor
981     BND_COLOR_TEXT, // textColor
982     BND_COLOR_TEXT_SELECTED, // textSelectedColor
983     -20, // shadeTop
984     0, // shadeDown
985   ),
986   // sliderTheme
987   BNDwidgetTheme(
988     "slider",
989     nvgRGBA( 24,  24,  24, 255), // outlineColor
990     nvgRGBA(128, 128, 128, 255), // itemColor
991     nvgRGBA(180, 180, 180, 255), // innerColor
992     nvgRGBA(153, 153, 153, 255), // innerSelectedColor
993     BND_COLOR_TEXT, // textColor
994     BND_COLOR_TEXT_SELECTED, // textSelectedColor
995     -20, // shadeTop
996     0, // shadeDown
997   ),
998   // scrollBarTheme
999   BNDwidgetTheme(
1000     "scrollbar",
1001     nvgRGBA( 49,  49,  49, 255), // outlineColor
1002     nvgRGBA(128, 128, 128, 255), // itemColor
1003     nvgRGBA( 80,  80,  80, 180), // innerColor
1004     nvgRGBA( 99,  99,  99, 180), // innerSelectedColor
1005     BND_COLOR_TEXT, // textColor
1006     BND_COLOR_TEXT_SELECTED, // textSelectedColor
1007     5, // shadeTop
1008     -5, // shadeDown
1009   ),
1010   // tooltipTheme
1011   BNDwidgetTheme(
1012     "tooltip",
1013     nvgRGBA(  0,   0,   0, 255), // outlineColor
1014     nvgRGBA( 99,  99,  99, 255), // itemColor
1015     nvgRGBA( 24,  24,  24, 230), // innerColor
1016     nvgRGBA( 44,  44,  44, 230), // innerSelectedColor
1017     nvgRGBA(159, 159, 159, 255), // textColor
1018     BND_COLOR_TEXT_SELECTED, // textSelectedColor
1019     0, // shadeTop
1020     0, // shadeDown
1021   ),
1022   // menuTheme
1023   BNDwidgetTheme(
1024     "menu",
1025     nvgRGBA(  0,   0,   0, 255), // outlineColor
1026     nvgRGBA( 99,  99,  99, 255), // itemColor
1027     nvgRGBA( 24,  24,  24, 230), // innerColor
1028     nvgRGBA( 44,  44,  44, 230), // innerSelectedColor
1029     nvgRGBA(159, 159, 159, 255), // textColor
1030     BND_COLOR_TEXT_SELECTED, // textSelectedColor
1031     0, // shadeTop
1032     0, // shadeDown
1033   ),
1034   // menuItemTheme
1035   BNDwidgetTheme(
1036     "menu item",
1037     nvgRGBA(  0,   0,   0, 255), // outlineColor
1038     nvgRGBA(172, 172, 172, 128), // itemColor
1039     nvgRGBA(  0, 100, 180, 255), // innerColor
1040     BND_COLOR_ACTIVE, // innerSelectedColor
1041     BND_COLOR_TEXT_SELECTED, // textColor
1042     BND_COLOR_TEXT, // textSelectedColor
1043     38, // shadeTop
1044     0, // shadeDown
1045     nvgRGBA(255, 255, 255, 255), // textHoverColor
1046   ),
1047   // nodeTheme
1048   BNDnodeTheme(
1049     "node",
1050     nvgRGBA(240,  87,   0, 255), // nodeSelectedColor
1051     nvgRGBA(  0,   0,   0, 255), // wiresColor
1052     nvgRGBA(126, 111, 111, 255), // textSelectedColor
1053     nvgRGBA(255, 170,  64, 255), // activeNodeColor
1054     nvgRGBA(255, 255, 255, 255), // wireSelectColor
1055     nvgRGBA(155, 155, 155, 159), // nodeBackdropColor
1056     5, // noodleCurving
1057   ),
1058 );
1059 
1060 ////////////////////////////////////////////////////////////////////////////////
1061 
1062 /// Sets the current theme all widgets will be drawn with. the default Blender 2.6 theme is set by default.
1063 public void bndSetTheme (in ref BNDtheme theme) { bndTheme = theme; }
1064 
1065 /// Returns the currently set theme
1066 public BNDtheme* bndGetTheme () { return &bndTheme; }
1067 
1068 // the handle to the image containing the icon sheet
1069 private __gshared NVGImage bndIconImage;
1070 
1071 //HACK!
1072 //shared static ~this () { bndIconImage.clear(); }
1073 
1074 /** Designates an image handle as returned by nvgCreateImage*() as the themes'
1075  * icon sheet. The icon sheet format must be compatible to Blender 2.6's icon
1076  * sheet; the order of icons does not matter.
1077  *
1078  * A valid icon sheet is e.g. shown at
1079  * http://wiki.blender.org/index.php/Dev:2.5/Doc/How_to/Add_an_icon
1080  *
1081  * $(WARNING Icon sheet image should not outlive it's parent context! Use [bndClearIconImage] before context deletion.)
1082  */
1083 public void bndSetIconImage() (in auto ref NVGImage image) nothrow @trusted @nogc { version(aliced) pragma(inline, true); bndIconImage = image; }
1084 
1085 /// Clears current icon image.
1086 public void bndClearIconImage () nothrow @trusted @nogc { version(aliced) pragma(inline, true); bndIconImage.clear(); }
1087 
1088 /// Returns icon sheet image.
1089 public NVGImage bndGetIconImage () nothrow @trusted @nogc { version(aliced) pragma(inline, true); return bndIconImage; }
1090 
1091 // the handle to the UI font
1092 private __gshared int bndFont = -1;
1093 private __gshared string bndFontFace = null;
1094 
1095 /** Designates an image handle as returned by nvgCreateFont*() as the themes'
1096  * UI font. Blender's original UI font Droid Sans is perfectly suited and
1097  * available here:
1098  * https://svn.blender.org/svnroot/bf-blender/trunk/blender/release/datafiles/fonts/
1099  */
1100 public void bndSetFont (int font) nothrow @trusted @nogc { pragma(inline, true); bndFont = font; bndFontFace = null; }
1101 
1102 /** Designates an image handle as returned by nvgCreateFont*() as the themes'
1103  * UI font. Blender's original UI font Droid Sans is perfectly suited and
1104  * available here:
1105  * https://svn.blender.org/svnroot/bf-blender/trunk/blender/release/datafiles/fonts/
1106  */
1107 public void bndSetFont (string font) nothrow @trusted @nogc { pragma(inline, true); bndFont = -1; bndFontFace = font; }
1108 
1109 public struct BndFontSaviour {
1110   int bndFont = -1;
1111   string bndFontFace = null;
1112 }
1113 
1114 /// Returns opaque object with the current font.
1115 public BndFontSaviour bndGetFont () nothrow @trusted @nogc { pragma(inline, true); return BndFontSaviour(bndFont, bndFontFace); }
1116 
1117 /// Sets current font from the opaque object, returned by [bndGetFont].
1118 public void bndSetFont (in BndFontSaviour fsv) nothrow @trusted @nogc { pragma(inline, true); bndFont = fsv.bndFont; bndFontFace = fsv.bndFontFace; }
1119 
1120 
1121 // returns `true` if font *looks* like valid
1122 public bool bndRealizeFont (NVGContext ctx) nothrow @trusted @nogc {
1123   if (ctx is null) return false;
1124   if (bndFont >= 0) { ctx.fontFaceId = bndFont; return true; }
1125   if (bndFontFace.length) { ctx.fontFace = bndFontFace; return true; }
1126   return false;
1127 }
1128 
1129 
1130 ////////////////////////////////////////////////////////////////////////////////
1131 /// High Level Functions. Use these functions to draw themed widgets with your NVGcontext.
1132 
1133 /** Draw a label with its lower left origin at (x, y) and size of (w, h).
1134  *
1135  * if iconid >= 0, an icon will be added to the widget
1136  *
1137  * if label is not null, a label will be added to the widget
1138  *
1139  * widget looks best when height is BND_WIDGET_HEIGHT
1140  */
1141 public void bndLabel(T=char) (NVGContext ctx, float x, float y, float w, float h, int iconid, const(T)[] label, int align_=BND_LEFT)
1142 if (isAnyCharType!T)
1143 {
1144   bndIconLabelValue(ctx, x, y, w, h, iconid, bndTheme.regularTheme.textColor, /*BND_LEFT*/align_, BND_LABEL_FONT_SIZE, label);
1145 }
1146 
1147 /** Draw a tool button  with its lower left origin at (x, y) and size of (w, h),
1148  * where flags is one or multiple flags from BNDcornerFlags and state denotes
1149  * the widgets current UI state.
1150  *
1151  * if iconid >= 0, an icon will be added to the widget
1152  *
1153  * if label is not null, a label will be added to the widget
1154  *
1155  * widget looks best when height is BND_WIDGET_HEIGHT
1156  */
1157 public void bndToolButton(T=char) (NVGContext ctx, float x, float y, float w, float h, int flags, BNDwidgetState state, int iconid, const(T)[] label)
1158 if (isAnyCharType!T)
1159 {
1160   float[4] cr = void;
1161   NVGColor shadeTop, shadeDown;
1162   bndSelectCorners(cr[], BND_TOOL_RADIUS, flags);
1163   bndBevelInset(ctx, x, y, w, h, cr[2], cr[3]);
1164   bndInnerColors(&shadeTop, &shadeDown, &bndTheme.toolTheme, state, 1);
1165   bndInnerBox(ctx, x, y, w, h, cr[0], cr[1], cr[2], cr[3], shadeTop, shadeDown);
1166   bndOutlineBox(ctx, x, y, w, h, cr[0], cr[1], cr[2], cr[3], bndTransparent(bndTheme.toolTheme.outlineColor));
1167   bndIconLabelValue(ctx, x, y, w, h, iconid, bndTextColor(&bndTheme.toolTheme, state), BND_CENTER, BND_LABEL_FONT_SIZE, label);
1168 }
1169 
1170 /** Draw a radio button with its lower left origin at (x, y) and size of (w, h),
1171  * where flags is one or multiple flags from BNDcornerFlags and state denotes
1172  * the widgets current UI state.
1173  *
1174  * if iconid >= 0, an icon will be added to the widget
1175  *
1176  * if label is not null, a label will be added to the widget
1177  *
1178  * widget looks best when height is BND_WIDGET_HEIGHT
1179  */
1180 public void bndRadioButton(T=char) (NVGContext ctx, float x, float y, float w, float h, int flags, BNDwidgetState state, int iconid, const(T)[] label)
1181 if (isAnyCharType!T)
1182 {
1183   float[4] cr = void;
1184   NVGColor shadeTop, shadeDown;
1185   bndSelectCorners(cr[], BND_OPTION_RADIUS, flags);
1186   bndBevelInset(ctx, x, y, w, h, cr[2], cr[3]);
1187   bndInnerColors(&shadeTop, &shadeDown, &bndTheme.radioTheme, state, 1);
1188   bndInnerBox(ctx, x, y, w, h, cr[0], cr[1], cr[2], cr[3], shadeTop, shadeDown);
1189   bndOutlineBox(ctx, x, y, w, h, cr[0], cr[1], cr[2], cr[3], bndTransparent(bndTheme.radioTheme.outlineColor));
1190   bndIconLabelValue(ctx, x, y, w, h, iconid, bndTextColor(&bndTheme.radioTheme, state), BND_CENTER, BND_LABEL_FONT_SIZE, label);
1191 }
1192 
1193 /** Draw a radio button with its lower left origin at (x, y) and size of (w, h),
1194  * where flags is one or multiple flags from BNDcornerFlags and state denotes
1195  * the widgets current UI state.
1196  *
1197  * if iconid >= 0, an icon will be added to the widget
1198  *
1199  * if label is not null, a label will be added to the widget
1200  *
1201  * widget looks best when height is BND_WIDGET_HEIGHT
1202  */
1203 public void bndRadioButton2(T=char) (NVGContext ctx, float x, float y, float w, float h, int flags, BNDwidgetState state, int iconid, const(T)[] label)
1204 if (isAnyCharType!T)
1205 {
1206   float ox, oy;
1207   NVGColor shadeTop, shadeDown;
1208   ox = x;
1209   oy = y+h-BND_OPTION_HEIGHT-3;
1210   bndBevelInset(ctx, ox, oy, BND_OPTION_WIDTH, BND_OPTION_HEIGHT, BND_OPTION_RADIUS, BND_OPTION_RADIUS);
1211   bndInnerColors(&shadeTop, &shadeDown, &bndTheme.optionTheme, state, 1);
1212   bndInnerBox(ctx, ox, oy, BND_OPTION_WIDTH, BND_OPTION_HEIGHT, BND_OPTION_RADIUS, BND_OPTION_RADIUS, BND_OPTION_RADIUS, BND_OPTION_RADIUS, shadeTop, shadeDown);
1213   bndOutlineBox(ctx, ox, oy, BND_OPTION_WIDTH, BND_OPTION_HEIGHT, BND_OPTION_RADIUS, BND_OPTION_RADIUS, BND_OPTION_RADIUS, BND_OPTION_RADIUS, bndTransparent(bndTheme.optionTheme.outlineColor));
1214   if (state == BND_ACTIVE) bndRadioCheck(ctx, ox, oy, bndTransparent(bndTheme.optionTheme.itemColor));
1215   bndIconLabelValue(ctx, x+12, y, w-12, h, -1, bndTextColor(&bndTheme.optionTheme, state), BND_LEFT, BND_LABEL_FONT_SIZE, label);
1216 }
1217 
1218 /** Calculate the corresponding text position for given coordinates px/py
1219  * in a text field.
1220  * See bndTextField for more info.
1221  */
1222 public int bndTextFieldTextPosition(T=char) (NVGContext ctx, float x, float y, float w, float h, int iconid, const(T)[] text, int px, int py)
1223 if (isAnyCharType!T)
1224 {
1225   return bndIconLabelTextPosition(ctx, x, y, w, h, iconid, BND_LABEL_FONT_SIZE, text, px, py);
1226 }
1227 
1228 /** Draw a text field with its lower left origin at (x, y) and size of (w, h),
1229  * where flags is one or multiple flags from BNDcornerFlags and state denotes
1230  * the widgets current UI state.
1231  *
1232  * if iconid >= 0, an icon will be added to the widget
1233  *
1234  * if text is not null, text will be printed to the widget
1235  *
1236  * cbegin must be >= 0 and <= strlen(text) and denotes the beginning of the caret
1237  *
1238  * cend must be >= cbegin and <= strlen(text) and denotes the end of the caret
1239  *
1240  * if cend < cbegin, then no caret will be drawn
1241  *
1242  * widget looks best when height is BND_WIDGET_HEIGHT
1243  */
1244 public void bndTextField(T=char) (NVGContext ctx, float x, float y, float w, float h, int flags, BNDwidgetState state, int iconid, const(T)[] text, int cbegin, int cend)
1245 if (isAnyCharType!T)
1246 {
1247   float[4] cr = void;
1248   NVGColor shadeTop, shadeDown;
1249   bndSelectCorners(cr[], BND_TEXT_RADIUS, flags);
1250   bndBevelInset(ctx, x, y, w, h, cr[2], cr[3]);
1251   bndInnerColors(&shadeTop, &shadeDown, &bndTheme.textFieldTheme, state, 0);
1252   bndInnerBox(ctx, x, y, w, h, cr[0], cr[1], cr[2], cr[3], shadeTop, shadeDown);
1253   bndOutlineBox(ctx, x, y, w, h, cr[0], cr[1], cr[2], cr[3], bndTransparent(bndTheme.textFieldTheme.outlineColor));
1254   if (state != BND_ACTIVE) cend = -1;
1255   NVGColor cc = bndTheme.textFieldTheme.textCaretColor;
1256   if (cc.isTransparent) cc = bndTheme.textFieldTheme.textColor;
1257   bndIconLabelCaret(ctx, x, y, w, h, iconid, bndTextColor(&bndTheme.textFieldTheme, state), BND_LABEL_FONT_SIZE, text, bndTheme.textFieldTheme.itemColor, cbegin, cend, cc);
1258 }
1259 
1260 /** Draw an option button with its lower left origin at (x, y) and size of (w, h),
1261  * where flags is one or multiple flags from BNDcornerFlags and state denotes
1262  * the widgets current UI state.
1263  *
1264  * if label is not null, a label will be added to the widget
1265  *
1266  * widget looks best when height is BND_WIDGET_HEIGHT
1267  */
1268 public void bndOptionButton(T=char) (NVGContext ctx, float x, float y, float w, float h, BNDwidgetState state, const(T)[] label)
1269 if (isAnyCharType!T)
1270 {
1271   float ox, oy;
1272   NVGColor shadeTop, shadeDown;
1273   ox = x;
1274   oy = y+h-BND_OPTION_HEIGHT-3;
1275   bndBevelInset(ctx, ox, oy, BND_OPTION_WIDTH, BND_OPTION_HEIGHT, BND_OPTION_RADIUS, BND_OPTION_RADIUS);
1276   bndInnerColors(&shadeTop, &shadeDown, &bndTheme.optionTheme, state, 1);
1277   bndInnerBox(ctx, ox, oy, BND_OPTION_WIDTH, BND_OPTION_HEIGHT, BND_OPTION_RADIUS, BND_OPTION_RADIUS, BND_OPTION_RADIUS, BND_OPTION_RADIUS, shadeTop, shadeDown);
1278   bndOutlineBox(ctx, ox, oy, BND_OPTION_WIDTH, BND_OPTION_HEIGHT, BND_OPTION_RADIUS, BND_OPTION_RADIUS, BND_OPTION_RADIUS, BND_OPTION_RADIUS, bndTransparent(bndTheme.optionTheme.outlineColor));
1279   if (state == BND_ACTIVE) bndCheck(ctx, ox, oy, bndTransparent(bndTheme.optionTheme.itemColor));
1280   bndIconLabelValue(ctx, x+12, y, w-12, h, -1, bndTextColor(&bndTheme.optionTheme, state), BND_LEFT, BND_LABEL_FONT_SIZE, label);
1281 }
1282 
1283 /** Draw a choice button with its lower left origin at (x, y) and size of (w, h),
1284  * where flags is one or multiple flags from BNDcornerFlags and state denotes
1285  * the widgets current UI state.
1286  *
1287  * if iconid >= 0, an icon will be added to the widget
1288  *
1289  * if label is not null, a label will be added to the widget
1290  *
1291  * widget looks best when height is BND_WIDGET_HEIGHT
1292  */
1293 public void bndChoiceButton(T=char) (NVGContext ctx, float x, float y, float w, float h, int flags, BNDwidgetState state, int iconid, const(T)[] label)
1294 if (isAnyCharType!T)
1295 {
1296   float[4] cr = void;
1297   NVGColor shadeTop, shadeDown;
1298   bndSelectCorners(cr[], BND_OPTION_RADIUS, flags);
1299   bndBevelInset(ctx, x, y, w, h, cr[2], cr[3]);
1300   bndInnerColors(&shadeTop, &shadeDown, &bndTheme.choiceTheme, state, 1);
1301   bndInnerBox(ctx, x, y, w, h, cr[0], cr[1], cr[2], cr[3], shadeTop, shadeDown);
1302   bndOutlineBox(ctx, x, y, w, h, cr[0], cr[1], cr[2], cr[3], bndTransparent(bndTheme.choiceTheme.outlineColor));
1303   bndIconLabelValue(ctx, x, y, w, h, iconid, bndTextColor(&bndTheme.choiceTheme, state), BND_LEFT, BND_LABEL_FONT_SIZE, label);
1304   bndUpDownArrow(ctx, x+w-10, y+10, 5, bndTransparent(bndTheme.choiceTheme.itemColor));
1305 }
1306 
1307 /** Draw a color button  with its lower left origin at (x, y) and size of (w, h),
1308  * where flags is one or multiple flags from BNDcornerFlags and state denotes
1309  * the widgets current UI state.
1310  *
1311  * widget looks best when height is BND_WIDGET_HEIGHT
1312  */
1313 public void bndColorButton (NVGContext ctx, float x, float y, float w, float h, int flags, NVGColor color) {
1314   float[4] cr = void;
1315   bndSelectCorners(cr[], BND_TOOL_RADIUS, flags);
1316   bndBevelInset(ctx, x, y, w, h, cr[2], cr[3]);
1317   bndInnerBox(ctx, x, y, w, h, cr[0], cr[1], cr[2], cr[3], color, color);
1318   bndOutlineBox(ctx, x, y, w, h, cr[0], cr[1], cr[2], cr[3], bndTransparent(bndTheme.toolTheme.outlineColor));
1319 }
1320 
1321 /** Draw a number field with its lower left origin at (x, y) and size of (w, h),
1322  * where flags is one or multiple flags from BNDcornerFlags and state denotes
1323  * the widgets current UI state.
1324  *
1325  * if label is not null, a label will be added to the widget
1326  *
1327  * if value is not null, a value will be added to the widget, along with a ":" separator
1328  *
1329  * widget looks best when height is BND_WIDGET_HEIGHT
1330  */
1331 public void bndNumberField(T=char) (NVGContext ctx, float x, float y, float w, float h, int flags, BNDwidgetState state, const(T)[] label, const(char)[] value)
1332 if (isAnyCharType!T)
1333 {
1334   float[4] cr = void;
1335   NVGColor shadeTop, shadeDown;
1336   bndSelectCorners(cr[], BND_NUMBER_RADIUS, flags);
1337   bndBevelInset(ctx, x, y, w, h, cr[2], cr[3]);
1338   bndInnerColors(&shadeTop, &shadeDown, &bndTheme.numberFieldTheme, state, 0);
1339   bndInnerBox(ctx, x, y, w, h, cr[0], cr[1], cr[2], cr[3], shadeTop, shadeDown);
1340   bndOutlineBox(ctx, x, y, w, h, cr[0], cr[1], cr[2], cr[3], bndTransparent(bndTheme.numberFieldTheme.outlineColor));
1341   bndIconLabelValue(ctx, x, y, w, h, -1, bndTextColor(&bndTheme.numberFieldTheme, state), BND_CENTER, BND_LABEL_FONT_SIZE, label, value);
1342   bndArrow(ctx, x+8, y+10, -BND_NUMBER_ARROW_SIZE, bndTransparent(bndTheme.numberFieldTheme.itemColor));
1343   bndArrow(ctx, x+w-8, y+10, BND_NUMBER_ARROW_SIZE, bndTransparent(bndTheme.numberFieldTheme.itemColor));
1344 }
1345 
1346 /** Draw slider control with its lower left origin at (x, y) and size of (w, h),
1347  * where flags is one or multiple flags from BNDcornerFlags and state denotes
1348  * the widgets current UI state.
1349  *
1350  * progress must be in the range 0..1 and controls the size of the slider bar
1351  *
1352  * if label is not null, a label will be added to the widget
1353  *
1354  * if value is not null, a value will be added to the widget, along with a ":" separator
1355  *
1356  * widget looks best when height is BND_WIDGET_HEIGHT
1357  */
1358 public void bndSlider(T=char,TV=char) (NVGContext ctx, float x, float y, float w, float h, int flags, BNDwidgetState state, float progress, const(T)[] label, const(TV)[] value)
1359 if (isAnyCharType!T && isAnyCharType!TV)
1360 {
1361   float[4] cr = void;
1362   NVGColor shadeTop, shadeDown;
1363 
1364   bndSelectCorners(cr[], BND_NUMBER_RADIUS, flags);
1365   bndBevelInset(ctx, x, y, w, h, cr[2], cr[3]);
1366   bndInnerColors(&shadeTop, &shadeDown, &bndTheme.sliderTheme, state, 0);
1367   bndInnerBox(ctx, x, y, w, h, cr[0], cr[1], cr[2], cr[3], shadeTop, shadeDown);
1368 
1369   if (state == BND_ACTIVE) {
1370     shadeTop = bndOffsetColor(bndTheme.sliderTheme.itemColor, bndTheme.sliderTheme.shadeTop);
1371     shadeDown = bndOffsetColor(bndTheme.sliderTheme.itemColor, bndTheme.sliderTheme.shadeDown);
1372   } else {
1373     shadeTop = bndOffsetColor(bndTheme.sliderTheme.itemColor, bndTheme.sliderTheme.shadeDown);
1374     shadeDown = bndOffsetColor(bndTheme.sliderTheme.itemColor, bndTheme.sliderTheme.shadeTop);
1375   }
1376   ctx.scissor(x, y, 8+(w-8)*bndClamp(progress, 0, 1), h);
1377   bndInnerBox(ctx, x, y, w, h, cr[0], cr[1], cr[2], cr[3], shadeTop, shadeDown);
1378   ctx.resetScissor();
1379 
1380   bndOutlineBox(ctx, x, y, w, h, cr[0], cr[1], cr[2], cr[3], bndTransparent(bndTheme.sliderTheme.outlineColor));
1381   bndIconLabelValue(ctx, x, y, w, h, -1, bndTextColor(&bndTheme.sliderTheme, state), BND_CENTER, BND_LABEL_FONT_SIZE, label, value);
1382 }
1383 
1384 /** Draw scrollbar with its lower left origin at (x, y) and size of (w, h),
1385  * where state denotes the widgets current UI state.
1386  *
1387  * offset is in the range 0..1 and controls the position of the scroll handle
1388  *
1389  * size is in the range 0..1 and controls the size of the scroll handle
1390  *
1391  * horizontal widget looks best when height is BND_SCROLLBAR_HEIGHT,
1392  *
1393  * vertical looks best when width is BND_SCROLLBAR_WIDTH
1394  */
1395 public void bndScrollBar (NVGContext ctx, float x, float y, float w, float h, BNDwidgetState state, float offset, float size) {
1396   bndBevelInset(ctx, x, y, w, h, BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS);
1397   bndInnerBox(ctx, x, y, w, h,
1398     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1399     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1400     bndOffsetColor(bndTheme.scrollBarTheme.innerColor, 3*bndTheme.scrollBarTheme.shadeDown),
1401     bndOffsetColor(bndTheme.scrollBarTheme.innerColor, 3*bndTheme.scrollBarTheme.shadeTop));
1402   bndOutlineBox(ctx, x, y, w, h,
1403     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1404     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1405     bndTransparent(bndTheme.scrollBarTheme.outlineColor));
1406 
1407   NVGColor itemColor = bndOffsetColor(bndTheme.scrollBarTheme.itemColor, (state == BND_ACTIVE ? BND_SCROLLBAR_ACTIVE_SHADE : 0));
1408 
1409   bndScrollHandleRect(&x, &y, &w, &h, offset, size);
1410 
1411   bndInnerBox(ctx, x, y, w, h,
1412     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1413     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1414     bndOffsetColor(itemColor, 3*bndTheme.scrollBarTheme.shadeTop),
1415     bndOffsetColor(itemColor, 3*bndTheme.scrollBarTheme.shadeDown));
1416   bndOutlineBox(ctx, x, y, w, h,
1417     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1418     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1419     bndTransparent(bndTheme.scrollBarTheme.outlineColor));
1420 }
1421 
1422 /** Draw scrollbar with its lower left origin at (x, y) and size of (w, h),
1423  * where state denotes the widgets current UI state.
1424  *
1425  * offset is in the range 0..1 and controls the position of the scroll handle
1426  *
1427  * size is in the range 0..1 and controls the size of the scroll handle
1428  *
1429  * horizontal widget looks best when height is BND_SCROLLBAR_HEIGHT,
1430  *
1431  * vertical looks best when width is BND_SCROLLBAR_WIDTH
1432  */
1433 public void bndScrollSlider (NVGContext ctx, float x, float y, float w, float h, BNDwidgetState state, float offset, float size=0) {
1434   bndBevelInset(ctx, x, y, w, h, BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS);
1435   bndInnerBox(ctx, x, y, w, h,
1436     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1437     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1438     bndOffsetColor(bndTheme.scrollBarTheme.innerColor, 3*bndTheme.scrollBarTheme.shadeDown),
1439     bndOffsetColor(bndTheme.scrollBarTheme.innerColor, 3*bndTheme.scrollBarTheme.shadeTop));
1440   bndOutlineBox(ctx, x, y, w, h,
1441     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1442     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1443     bndTransparent(bndTheme.scrollBarTheme.outlineColor));
1444 
1445   NVGColor itemColor = bndOffsetColor(bndTheme.scrollBarTheme.itemColor, (state == BND_ACTIVE ? BND_SCROLLBAR_ACTIVE_SHADE : 0));
1446 
1447   bndScrollSliderRect(&w, &h, offset, size);
1448 
1449   bndInnerBox(ctx, x, y, w, h,
1450     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1451     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1452     bndOffsetColor(itemColor, 3*bndTheme.scrollBarTheme.shadeTop),
1453     bndOffsetColor(itemColor, 3*bndTheme.scrollBarTheme.shadeDown));
1454   bndOutlineBox(ctx, x, y, w, h,
1455     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1456     BND_SCROLLBAR_RADIUS, BND_SCROLLBAR_RADIUS,
1457     bndTransparent(bndTheme.scrollBarTheme.outlineColor));
1458 }
1459 
1460 /** Draw a menu background with its lower left origin at (x, y) and size of (w, h),
1461  * where flags is one or multiple flags from BNDcornerFlags.
1462  */
1463 public void bndMenuBackground (NVGContext ctx, float x, float y, float w, float h, int flags) {
1464   float[4] cr = void;
1465   NVGColor shadeTop, shadeDown;
1466   bndSelectCorners(cr[], BND_MENU_RADIUS, flags);
1467   bndInnerColors(&shadeTop, &shadeDown, &bndTheme.menuTheme, BND_DEFAULT, 0);
1468   bndInnerBox(ctx, x, y, w, h+1, cr[0], cr[1], cr[2], cr[3], shadeTop, shadeDown);
1469   bndOutlineBox(ctx, x, y, w, h+1, cr[0], cr[1], cr[2], cr[3], bndTransparent(bndTheme.menuTheme.outlineColor));
1470   bndDropShadow(ctx, x, y, w, h, BND_MENU_RADIUS, BND_SHADOW_FEATHER, BND_SHADOW_ALPHA);
1471 }
1472 
1473 /// Draw a tooltip background with its lower left origin at (x, y) and size of (w, h)
1474 public void bndTooltipBackground (NVGContext ctx, float x, float y, float w, float h) {
1475   NVGColor shadeTop, shadeDown;
1476   bndInnerColors(&shadeTop, &shadeDown, &bndTheme.tooltipTheme, BND_DEFAULT, 0);
1477   bndInnerBox(ctx, x, y, w, h+1, BND_MENU_RADIUS, BND_MENU_RADIUS, BND_MENU_RADIUS, BND_MENU_RADIUS, shadeTop, shadeDown);
1478   bndOutlineBox(ctx, x, y, w, h+1, BND_MENU_RADIUS, BND_MENU_RADIUS, BND_MENU_RADIUS, BND_MENU_RADIUS, bndTransparent(bndTheme.tooltipTheme.outlineColor));
1479   bndDropShadow(ctx, x, y, w, h, BND_MENU_RADIUS, BND_SHADOW_FEATHER, BND_SHADOW_ALPHA);
1480 }
1481 
1482 /** Draw a menu label with its lower left origin at (x, y) and size of (w, h).
1483  *
1484  * if iconid >= 0, an icon will be added to the widget
1485  *
1486  * if label is not null, a label will be added to the widget
1487  *
1488  * widget looks best when height is BND_WIDGET_HEIGHT
1489  */
1490 public void bndMenuLabel(T=char) (NVGContext ctx, float x, float y, float w, float h, int iconid, const(T)[] label)
1491 if (isAnyCharType!T)
1492 {
1493   bndIconLabelValue(ctx, x, y, w, h, iconid, bndTheme.menuTheme.textColor, BND_LEFT, BND_LABEL_FONT_SIZE, label);
1494 }
1495 
1496 /** Draw a menu item with its lower left origin at (x, y) and size of (w, h),
1497  * where state denotes the widgets current UI state.
1498  *
1499  * if iconid >= 0, an icon will be added to the widget
1500  *
1501  * if label is not null, a label will be added to the widget
1502  *
1503  * widget looks best when height is BND_WIDGET_HEIGHT
1504  */
1505 public void bndMenuItem(T=char) (NVGContext ctx, float x, float y, float w, float h, BNDwidgetState state, int iconid, const(T)[] label)
1506 if (isAnyCharType!T)
1507 {
1508   if (state != BND_DEFAULT) {
1509     auto clr = (state == BND_HOVER ? bndOffsetColor(bndTheme.menuItemTheme.innerColor/*innerSelectedColor*/, BND_HOVER_SHADE) : bndTheme.menuItemTheme.innerSelectedColor);
1510     bndInnerBox(ctx, x, y, w, h, 0, 0, 0, 0,
1511       bndOffsetColor(clr, bndTheme.menuItemTheme.shadeTop),
1512       bndOffsetColor(clr, bndTheme.menuItemTheme.shadeDown));
1513     //state = BND_ACTIVE;
1514   }
1515   bndIconLabelValue(ctx, x, y, w, h, iconid,
1516     bndTextColor(&bndTheme.menuItemTheme, state), BND_LEFT,
1517     BND_LABEL_FONT_SIZE, label);
1518 }
1519 
1520 /// Draw a node port at the given position filled with the given color
1521 public void bndNodePort (NVGContext ctx, float x, float y, BNDwidgetState state, NVGColor color) {
1522   ctx.beginPath();
1523   ctx.circle(x, y, BND_NODE_PORT_RADIUS);
1524   ctx.strokeColor(bndTheme.nodeTheme.wiresColor);
1525   ctx.strokeWidth(1.0f);
1526   ctx.stroke();
1527   ctx.fillColor((state != BND_DEFAULT ? bndOffsetColor(color, BND_HOVER_SHADE) : color));
1528   ctx.fill();
1529 }
1530 
1531 /// Draw a node wire originating at (x0, y0) and floating to (x1, y1), with a colored gradient based on the two colors color0 and color1
1532 public void bndColoredNodeWire (NVGContext ctx, float x0, float y0, float x1, float y1, NVGColor color0, NVGColor color1) {
1533   import core.stdc.math : fabsf;
1534   float length = bndMax(fabsf(x1-x0), fabsf(y1-y0));
1535   float delta = length*cast(float)bndTheme.nodeTheme.noodleCurving/10.0f;
1536 
1537   ctx.beginPath();
1538   ctx.moveTo(x0, y0);
1539   ctx.bezierTo(x0+delta, y0, x1-delta, y1, x1, y1);
1540   NVGColor colorw = bndTheme.nodeTheme.wiresColor;
1541   colorw.a = (color0.a < color1.a ? color0.a : color1.a);
1542   ctx.strokeColor(colorw);
1543   ctx.strokeWidth(BND_NODE_WIRE_OUTLINE_WIDTH);
1544   ctx.stroke();
1545   ctx.strokePaint(ctx.linearGradient(x0, y0, x1, y1, color0, color1));
1546   ctx.strokeWidth(BND_NODE_WIRE_WIDTH);
1547   ctx.stroke();
1548 }
1549 
1550 /** Draw a node wire originating at (x0, y0) and floating to (x1, y1), with
1551  * a colored gradient based on the states state0 and state1:
1552  *
1553  * BND_DEFAULT: default wire color
1554  *
1555  * BND_HOVER: selected wire color
1556  *
1557  * BND_ACTIVE: dragged wire color
1558  */
1559 public void bndNodeWire (NVGContext ctx, float x0, float y0, float x1, float y1, BNDwidgetState state0, BNDwidgetState state1) {
1560   bndColoredNodeWire(ctx, x0, y0, x1, y1, bndNodeWireColor(&bndTheme.nodeTheme, state0), bndNodeWireColor(&bndTheme.nodeTheme, state1));
1561 }
1562 
1563 /// Draw a node background with its upper left origin at (x, y) and size of (w, h) where titleColor provides the base color for the title bar
1564 public void bndNodeBackground(T=char) (NVGContext ctx, float x, float y, float w, float h, BNDwidgetState state, int iconid, const(T)[] label, NVGColor titleColor)
1565 if (isAnyCharType!T)
1566 {
1567   bndInnerBox(ctx, x, y, w, BND_NODE_TITLE_HEIGHT+2,
1568       BND_NODE_RADIUS, BND_NODE_RADIUS, 0, 0,
1569       bndTransparent(bndOffsetColor(titleColor, BND_BEVEL_SHADE)),
1570       bndTransparent(titleColor));
1571   bndInnerBox(ctx, x, y+BND_NODE_TITLE_HEIGHT-1, w, h+2-BND_NODE_TITLE_HEIGHT,
1572       0, 0, BND_NODE_RADIUS, BND_NODE_RADIUS,
1573       bndTransparent(bndTheme.nodeTheme.nodeBackdropColor),
1574       bndTransparent(bndTheme.nodeTheme.nodeBackdropColor));
1575   bndNodeIconLabel(ctx,
1576       x+BND_NODE_ARROW_AREA_WIDTH, y,
1577       w-BND_NODE_ARROW_AREA_WIDTH-BND_NODE_MARGIN_SIDE, BND_NODE_TITLE_HEIGHT,
1578       iconid, bndTheme.regularTheme.textColor,
1579       bndOffsetColor(titleColor, BND_BEVEL_SHADE),
1580       BND_LEFT, BND_LABEL_FONT_SIZE, label);
1581   NVGColor arrowColor;
1582   NVGColor borderColor;
1583   switch (state) {
1584     default:
1585     case BND_DEFAULT:
1586       borderColor = nvgRGBf(0, 0, 0);
1587       arrowColor = bndOffsetColor(titleColor, -BND_BEVEL_SHADE);
1588       break;
1589     case BND_HOVER:
1590       borderColor = bndTheme.nodeTheme.nodeSelectedColor;
1591       arrowColor = bndTheme.nodeTheme.nodeSelectedColor;
1592       break;
1593     case BND_ACTIVE:
1594       borderColor = bndTheme.nodeTheme.activeNodeColor;
1595       arrowColor = bndTheme.nodeTheme.nodeSelectedColor;
1596       break;
1597   }
1598   bndOutlineBox(ctx, x, y, w, h+1, BND_NODE_RADIUS, BND_NODE_RADIUS, BND_NODE_RADIUS, BND_NODE_RADIUS, bndTransparent(borderColor));
1599   //bndNodeArrowDown(ctx, x+BND_NODE_MARGIN_SIDE, y+BND_NODE_TITLE_HEIGHT-4, BND_NODE_ARROW_SIZE, arrowColor);
1600   bndDropShadow(ctx, x, y, w, h, BND_NODE_RADIUS, BND_SHADOW_FEATHER, BND_SHADOW_ALPHA);
1601 }
1602 
1603 /// Draw a window with the upper right and lower left splitter widgets into the rectangle at origin (x, y) and size (w, h)
1604 public void bndSplitterWidgets (NVGContext ctx, float x, float y, float w, float h) {
1605   NVGColor insetLight = bndTransparent(bndOffsetColor(bndTheme.backgroundColor, BND_SPLITTER_SHADE));
1606   NVGColor insetDark = bndTransparent(bndOffsetColor(bndTheme.backgroundColor, -BND_SPLITTER_SHADE));
1607   NVGColor inset = bndTransparent(bndTheme.backgroundColor);
1608 
1609   float x2 = x+w;
1610   float y2 = y+h;
1611 
1612   ctx.beginPath();
1613   ctx.moveTo(x, y2-13);
1614   ctx.lineTo(x+13, y2);
1615   ctx.moveTo(x, y2-9);
1616   ctx.lineTo(x+9, y2);
1617   ctx.moveTo(x, y2-5);
1618   ctx.lineTo(x+5, y2);
1619 
1620   ctx.moveTo(x2-11, y);
1621   ctx.lineTo(x2, y+11);
1622   ctx.moveTo(x2-7, y);
1623   ctx.lineTo(x2, y+7);
1624   ctx.moveTo(x2-3, y);
1625   ctx.lineTo(x2, y+3);
1626 
1627   ctx.strokeColor(insetDark);
1628   ctx.stroke();
1629 
1630   ctx.beginPath();
1631   ctx.moveTo(x, y2-11);
1632   ctx.lineTo(x+11, y2);
1633   ctx.moveTo(x, y2-7);
1634   ctx.lineTo(x+7, y2);
1635   ctx.moveTo(x, y2-3);
1636   ctx.lineTo(x+3, y2);
1637 
1638   ctx.moveTo(x2-13, y);
1639   ctx.lineTo(x2, y+13);
1640   ctx.moveTo(x2-9, y);
1641   ctx.lineTo(x2, y+9);
1642   ctx.moveTo(x2-5, y);
1643   ctx.lineTo(x2, y+5);
1644 
1645   ctx.strokeColor(insetLight);
1646   ctx.stroke();
1647 
1648   ctx.beginPath();
1649   ctx.moveTo(x, y2-12);
1650   ctx.lineTo(x+12, y2);
1651   ctx.moveTo(x, y2-8);
1652   ctx.lineTo(x+8, y2);
1653   ctx.moveTo(x, y2-4);
1654   ctx.lineTo(x+4, y2);
1655 
1656   ctx.moveTo(x2-12, y);
1657   ctx.lineTo(x2, y+12);
1658   ctx.moveTo(x2-8, y);
1659   ctx.lineTo(x2, y+8);
1660   ctx.moveTo(x2-4, y);
1661   ctx.lineTo(x2, y+4);
1662 
1663   ctx.strokeColor(inset);
1664   ctx.stroke();
1665 }
1666 
1667 /** Draw the join area overlay stencil into the rectangle
1668  * at origin (x, y) and size (w, h)
1669  *
1670  * vertical is `false` or `true` and designates the arrow orientation, mirror is `false` or `true` and flips the arrow side
1671  */
1672 public void bndJoinAreaOverlay (NVGContext ctx, float x, float y, float w, float h, bool vertical, bool mirror) {
1673   if (vertical) {
1674     float u = w;
1675     w = h; h = u;
1676   }
1677 
1678   float s = (w < h ? w : h);
1679 
1680   float x0, y0, x1, y1;
1681   if (mirror) {
1682     x0 = w;
1683     y0 = h;
1684     x1 = 0;
1685     y1 = 0;
1686     s = -s;
1687   } else {
1688     x0 = 0;
1689     y0 = 0;
1690     x1 = w;
1691     y1 = h;
1692   }
1693 
1694   float yc = (y0+y1)*0.5f;
1695   float s2 = s/2.0f;
1696   float s4 = s/4.0f;
1697   float s8 = s/8.0f;
1698   float x4 = x0+s4;
1699 
1700   float[2][11] points = [
1701     [ x0, y0 ],
1702     [ x1, y0 ],
1703     [ x1, y1 ],
1704     [ x0, y1 ],
1705     [ x0, yc+s8 ],
1706     [ x4, yc+s8 ],
1707     [ x4, yc+s4 ],
1708     [ x0+s2, yc ],
1709     [ x4, yc-s4 ],
1710     [ x4, yc-s8 ],
1711     [ x0, yc-s8 ]
1712   ];
1713 
1714   ctx.beginPath();
1715   int count = cast(int)points.length; //sizeof(points)/(sizeof(float)*2);
1716   ctx.moveTo(x+points[0][vertical&1], y+points[0][(vertical&1)^1]);
1717   foreach (int i; 1..count) ctx.lineTo(x+points[i][vertical&1], y+points[i][(vertical&1)^1]);
1718 
1719   ctx.fillColor(nvgRGBAf(0, 0, 0, 0.3));
1720   ctx.fill();
1721 }
1722 
1723 
1724 ////////////////////////////////////////////////////////////////////////////////
1725 /// Estimator Functions
1726 /// Use these functions to estimate sizes for widgets with your NVGcontext.
1727 
1728 /// returns the ideal width for a label with given icon and text
1729 public float bndLabelWidth(T=char) (NVGContext ctx, int iconid, const(T)[] label) if (isAnyCharType!T) {
1730   float w = BND_PAD_LEFT+BND_PAD_RIGHT;
1731   if (iconid >= 0) w += BND_ICON_SHEET_RES;
1732   if (label.length && bndRealizeFont(ctx)) {
1733     ctx.fontSize(BND_LABEL_FONT_SIZE);
1734     w += ctx.textBounds(1, 1, label, null);
1735   }
1736   return cast(float)cast(int)(w+0.5);
1737 }
1738 
1739 /// returns the height for a label with given icon, text and width; this function is primarily useful in conjunction with multiline labels and textboxes
1740 public float bndLabelHeight(T=char) (NVGContext ctx, int iconid, const(T)[] label, float width) if (isAnyCharType!T) {
1741   float h = BND_WIDGET_HEIGHT;
1742   width -= BND_TEXT_RADIUS*2;
1743   if (iconid >= 0) width -= BND_ICON_SHEET_RES;
1744   if (label.length && bndRealizeFont(ctx)) {
1745     ctx.fontSize(BND_LABEL_FONT_SIZE);
1746     float[4] bounds = void;
1747     ctx.textBoxBounds(1, 1, width, label, bounds[]);
1748     float bh = (bounds[3]-bounds[1])+BND_TEXT_PAD_DOWN;
1749     if (bh > h) h = bh;
1750   }
1751   return cast(float)cast(int)(h+0.5);
1752 }
1753 
1754 
1755 ////////////////////////////////////////////////////////////////////////////////
1756 /// Low Level Functions
1757 /// these are part of the implementation detail and can be used to theme new kinds of controls in a similar fashion.
1758 
1759 /** Add a rounded box path at position (x, y) with size (w, h) and a separate
1760  * radius for each corner listed in clockwise order, so that cr0 = top left,
1761  * cr1 = top right, cr2 = bottom right, cr3 = bottom left;
1762  *
1763  * this is a low level drawing function: the path must be stroked or filled
1764  * to become visible.
1765  */
1766 public void bndRoundedBox (NVGContext ctx, float x, float y, float w, float h, float cr0, float cr1, float cr2, float cr3) {
1767   float d;
1768   w = bndMax(0, w);
1769   h = bndMax(0, h);
1770   d = bndMin(w, h);
1771   ctx.moveTo(x, y+h*0.5f);
1772   ctx.arcTo(x, y, x+w, y, bndMin(cr0, d/2));
1773   ctx.arcTo(x+w, y, x+w, y+h, bndMin(cr1, d/2));
1774   ctx.arcTo(x+w, y+h, x, y+h, bndMin(cr2, d/2));
1775   ctx.arcTo(x, y+h, x, y, bndMin(cr3, d/2));
1776   ctx.closePath();
1777 }
1778 
1779 /// make color transparent using the default alpha value
1780 public NVGColor bndTransparent (NVGColor color) {
1781   color.a *= BND_TRANSPARENT_ALPHA;
1782   return color;
1783 }
1784 
1785 /// offset a color by a given integer delta in the range -100 to 100
1786 public NVGColor bndOffsetColor (NVGColor color, int delta) {
1787   float offset = cast(float)delta/255.0f;
1788   return (delta ? nvgRGBAf(bndClamp(color.r+offset, 0, 1), bndClamp(color.g+offset, 0, 1), bndClamp(color.b+offset, 0, 1), color.a) : color);
1789 }
1790 
1791 /// Draw a beveled border at position (x, y) with size (w, h) shaded with lighter and darker versions of backgroundColor
1792 public void bndBevel (NVGContext ctx, float x, float y, float w, float h) {
1793   ctx.strokeWidth(1);
1794 
1795   x += 0.5f;
1796   y += 0.5f;
1797   w -= 1;
1798   h -= 1;
1799 
1800   ctx.beginPath();
1801   ctx.moveTo(x, y+h);
1802   ctx.lineTo(x+w, y+h);
1803   ctx.lineTo(x+w, y);
1804   ctx.strokeColor(bndTransparent(bndOffsetColor(bndTheme.backgroundColor, -BND_BEVEL_SHADE)));
1805   ctx.stroke();
1806 
1807   ctx.beginPath();
1808   ctx.moveTo(x, y+h);
1809   ctx.lineTo(x, y);
1810   ctx.lineTo(x+w, y);
1811   ctx.strokeColor(bndTransparent(bndOffsetColor(bndTheme.backgroundColor, BND_BEVEL_SHADE)));
1812   ctx.stroke();
1813 }
1814 
1815 /** Draw a lower inset for a rounded box at position (x, y) with size (w, h)
1816  * that gives the impression the surface has been pushed in.
1817  *
1818  * cr2 and cr3 contain the radiuses of the bottom right and bottom left
1819  * corners of the rounded box.
1820  */
1821 public void bndBevelInset (NVGContext ctx, float x, float y, float w, float h, float cr2, float cr3) {
1822   float d;
1823 
1824   y -= 0.5f;
1825   d = bndMin(w, h);
1826   cr2 = bndMin(cr2, d/2);
1827   cr3 = bndMin(cr3, d/2);
1828 
1829   ctx.beginPath();
1830   ctx.moveTo(x+w, y+h-cr2);
1831   ctx.arcTo(x+w, y+h, x, y+h, cr2);
1832   ctx.arcTo(x, y+h, x, y, cr3);
1833 
1834   NVGColor bevelColor = bndOffsetColor(bndTheme.backgroundColor, BND_INSET_BEVEL_SHADE);
1835 
1836   ctx.strokeWidth(1);
1837   ctx.strokePaint(ctx.linearGradient(x, y+h-bndMax(cr2, cr3)-1, x, y+h-1, nvgRGBAf(bevelColor.r, bevelColor.g, bevelColor.b, 0), bevelColor));
1838   ctx.stroke();
1839 }
1840 
1841 /// Draw a flat panel without any decorations at position (x, y) with size (w, h) and fills it with backgroundColor
1842 public void bndBackground (NVGContext ctx, float x, float y, float w, float h) {
1843   ctx.beginPath();
1844   ctx.rect(x, y, w, h);
1845   ctx.fillColor(bndTheme.backgroundColor);
1846   ctx.fill();
1847 }
1848 
1849 /// 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.
1850 public void bndIcon (NVGContext ctx, float x, float y, int iconid) {
1851   int ix, iy, u, v;
1852   if (!bndIconImage.valid) return; // no icons loaded
1853 
1854   ix = iconid&0xff;
1855   iy = (iconid>>8)&0xff;
1856   u = BND_ICON_SHEET_OFFSET_X+ix*BND_ICON_SHEET_GRID;
1857   v = BND_ICON_SHEET_OFFSET_Y+iy*BND_ICON_SHEET_GRID;
1858 
1859   ctx.beginPath();
1860   ctx.rect(x, y, BND_ICON_SHEET_RES, BND_ICON_SHEET_RES);
1861   ctx.fillPaint(ctx.imagePattern(x-u, y-v, BND_ICON_SHEET_WIDTH, BND_ICON_SHEET_HEIGHT, 0, bndIconImage, 1));
1862   ctx.fill();
1863 }
1864 
1865 /** Draw a drop shadow around the rounded box at (x, y) with size (w, h) and
1866  * radius r, with feather as its maximum range in pixels.
1867  *
1868  * No shadow will be painted inside the rounded box.
1869  */
1870 public void bndDropShadow (NVGContext ctx, float x, float y, float w, float h, float r, float feather, float alpha) {
1871   ctx.beginPath();
1872   y += feather;
1873   h -= feather;
1874 
1875   ctx.moveTo(x-feather, y-feather);
1876   ctx.lineTo(x, y-feather);
1877   ctx.lineTo(x, y+h-feather);
1878   ctx.arcTo(x, y+h, x+r, y+h, r);
1879   ctx.arcTo(x+w, y+h, x+w, y+h-r, r);
1880   ctx.lineTo(x+w, y-feather);
1881   ctx.lineTo(x+w+feather, y-feather);
1882   ctx.lineTo(x+w+feather, y+h+feather);
1883   ctx.lineTo(x-feather, y+h+feather);
1884   ctx.closePath();
1885 
1886   ctx.fillPaint(ctx.boxGradient(x-feather*0.5f, y-feather*0.5f,
1887       w+feather, h+feather,
1888       r+feather*0.5f,
1889       feather,
1890       nvgRGBAf(0, 0, 0, alpha*alpha),
1891       nvgRGBAf(0, 0, 0, 0)));
1892   ctx.fill();
1893 }
1894 
1895 /* Draw the inner part of a widget box, with a gradient from shadeTop to
1896  * shadeDown. If h>w, the gradient will be horizontal instead of vertical.
1897  */
1898 public void bndInnerBox (NVGContext ctx, float x, float y, float w, float h, float cr0, float cr1, float cr2, float cr3, NVGColor shadeTop, NVGColor shadeDown) {
1899   ctx.beginPath();
1900   bndRoundedBox(ctx, x+1, y+1, w-2, h-3, bndMax(0, cr0-1), bndMax(0, cr1-1), bndMax(0, cr2-1), bndMax(0, cr3-1));
1901   ctx.fillPaint((h-2 > w ? ctx.linearGradient(x, y, x+w, y, shadeTop, shadeDown) : ctx.linearGradient(x, y, x, y+h, shadeTop, shadeDown)));
1902   ctx.fill();
1903 }
1904 
1905 /// Draw the outline part of a widget box with the given color
1906 public void bndOutlineBox (NVGContext ctx, float x, float y, float w, float h, float cr0, float cr1, float cr2, float cr3, NVGColor color) {
1907   ctx.beginPath();
1908   bndRoundedBox(ctx, x+0.5f, y+0.5f, w-1, h-2, cr0, cr1, cr2, cr3);
1909   ctx.strokeColor(color);
1910   ctx.strokeWidth(1);
1911   ctx.stroke();
1912 }
1913 
1914 /** assigns radius r to the four entries of array radiuses depending on whether
1915  * the corner is marked as sharp or not; see BNDcornerFlags for possible
1916  * flag values.
1917  */
1918 public void bndSelectCorners (float[] radiuses, float r, int flags) {
1919   if (radiuses.length > 0) radiuses.ptr[0] = (flags&BND_CORNER_TOP_LEFT ? 0 : r);
1920   if (radiuses.length > 1) radiuses.ptr[1] = (flags&BND_CORNER_TOP_RIGHT ? 0 : r);
1921   if (radiuses.length > 2) radiuses.ptr[2] = (flags&BND_CORNER_DOWN_RIGHT ? 0 : r);
1922   if (radiuses.length > 3) radiuses.ptr[3] = (flags&BND_CORNER_DOWN_LEFT ? 0 : r);
1923 }
1924 
1925 /** computes the upper and lower gradient colors for the inner box from a widget
1926  * theme and the widgets state. If flipActive is set and the state is
1927  * BND_ACTIVE, the upper and lower colors will be swapped.
1928  */
1929 public void bndInnerColors (NVGColor* shadeTop, NVGColor* shadeDown, const(BNDwidgetTheme)* theme, BNDwidgetState state, int flipActive) {
1930   switch (state) {
1931     default:
1932     case BND_DEFAULT:
1933       if (shadeTop !is null) *shadeTop = bndOffsetColor(theme.innerColor, theme.shadeTop);
1934       if (shadeDown !is null) *shadeDown = bndOffsetColor(theme.innerColor, theme.shadeDown);
1935       break;
1936     case BND_HOVER:
1937       NVGColor color = bndOffsetColor(theme.innerColor, BND_HOVER_SHADE);
1938       if (shadeTop !is null) *shadeTop = bndOffsetColor(color, theme.shadeTop);
1939       if (shadeDown !is null) *shadeDown = bndOffsetColor(color, theme.shadeDown);
1940       break;
1941     case BND_ACTIVE:
1942       if (shadeTop !is null) *shadeTop = bndOffsetColor(theme.innerSelectedColor, flipActive?theme.shadeDown:theme.shadeTop);
1943       if (shadeDown !is null) *shadeDown = bndOffsetColor(theme.innerSelectedColor, flipActive?theme.shadeTop:theme.shadeDown);
1944       break;
1945   }
1946 }
1947 
1948 /// computes the text color for a widget label from a widget theme and the widgets state.
1949 public NVGColor bndTextColor (const(BNDwidgetTheme)* theme, BNDwidgetState state) nothrow @trusted @nogc {
1950   pragma(inline, true);
1951   return
1952     state == BND_ACTIVE ? theme.textSelectedColor :
1953     state == BND_HOVER ? (theme.textHoverColor.isTransparent ? theme.textColor : theme.textHoverColor) :
1954     theme.textColor;
1955 }
1956 
1957 /** Draw an optional icon specified by <iconid> and an optional label with
1958  * given alignment (BNDtextAlignment), fontsize and color within a widget box.
1959  *
1960  * if iconid is >= 0, an icon will be drawn and the labels remaining space will be adjusted.
1961  *
1962  * if label is not null, it will be drawn with the specified alignment, fontsize and color.
1963  *
1964  * if value is not null, label and value will be drawn with a ":" separator inbetween.
1965  */
1966 public void bndIconLabelValue(T=char,TV=char) (NVGContext ctx, float x, float y, float w, float h, int iconid, NVGColor color, int align_, float fontsize, const(T)[] label, const(TV)[] value=null)
1967 if (isAnyCharType!T && isAnyCharType!TV)
1968 {
1969   float pleft = BND_PAD_LEFT;
1970   if (label.length) {
1971     if (iconid >= 0) {
1972       bndIcon(ctx, x+4, y+2, iconid);
1973       pleft += BND_ICON_SHEET_RES;
1974     }
1975 
1976     if (!bndRealizeFont(ctx)) return;
1977     ctx.fontSize(fontsize);
1978     ctx.beginPath();
1979     ctx.fillColor(color);
1980     if (value.length) {
1981       float label_width = ctx.textBounds(1, 1, label, null);
1982       float sep_width = ctx.textBounds(1, 1, BND_LABEL_SEPARATOR, null);
1983 
1984       ctx.textAlign(NVGTextAlign.H.Left, NVGTextAlign.V.Baseline);
1985       x += pleft;
1986       if (align_ == BND_CENTER) {
1987         float width = label_width+sep_width+ctx.textBounds(1, 1, value, null);
1988         x += ((w-BND_PAD_RIGHT-pleft)-width)*0.5f;
1989       } else if (align_ == BND_RIGHT) {
1990         float width = label_width+sep_width+ctx.textBounds(1, 1, value, null);
1991         x += w-BND_PAD_RIGHT-width;
1992       }
1993       y += BND_WIDGET_HEIGHT-BND_TEXT_PAD_DOWN;
1994       ctx.text(x, y, label);
1995       x += label_width;
1996       ctx.text(x, y, BND_LABEL_SEPARATOR);
1997       x += sep_width;
1998       ctx.text(x, y, value);
1999     } else {
2000       ctx.textAlign((align_ == BND_LEFT ? NVGTextAlign(NVGTextAlign.H.Left, NVGTextAlign.V.Baseline) : align_ == BND_CENTER ? NVGTextAlign(NVGTextAlign.H.Center, NVGTextAlign.V.Baseline) : NVGTextAlign(NVGTextAlign.H.Right, NVGTextAlign.V.Baseline)));
2001       ctx.textBox(x+pleft, y+BND_WIDGET_HEIGHT-BND_TEXT_PAD_DOWN, w-BND_PAD_RIGHT-pleft, label);
2002       //{ import core.stdc.stdio : printf; printf("l=%u\n", cast(uint)label.length); }
2003     }
2004   } else if (iconid >= 0) {
2005     bndIcon(ctx, x+2, y+2, iconid);
2006   }
2007 }
2008 
2009 /** Draw an optional icon specified by <iconid> and an optional label with
2010  * given alignment (BNDtextAlignment), fontsize and color within a node title bar
2011  *
2012  * if iconid is >= 0, an icon will be drawn
2013  *
2014  * if label is not null, it will be drawn with the specified alignment, fontsize and color.
2015  */
2016 public void bndNodeIconLabel(T=char) (NVGContext ctx, float x, float y, float w, float h, int iconid, NVGColor color, NVGColor shadowColor, int align_, float fontsize, const(T)[] label)
2017 if (isAnyCharType!T)
2018 {
2019   if (label.length && bndRealizeFont(ctx)) {
2020     ctx.fontSize(fontsize);
2021     ctx.beginPath();
2022     ctx.textAlign(NVGTextAlign.H.Left, NVGTextAlign.V.Baseline);
2023     ctx.fillColor(shadowColor);
2024     ctx.fontBlur(BND_NODE_TITLE_FEATHER);
2025     ctx.textBox(x+1, y+h+3-BND_TEXT_PAD_DOWN, w, label);
2026     ctx.fillColor(color);
2027     ctx.fontBlur(0);
2028     ctx.textBox(x, y+h+2-BND_TEXT_PAD_DOWN, w, label);
2029   }
2030   if (iconid >= 0) bndIcon(ctx, x+w-BND_ICON_SHEET_RES, y+3, iconid);
2031 }
2032 
2033 /** Calculate the corresponding text position for given coordinates px/py in an iconLabel.
2034  * See bndIconLabelCaret for more info.
2035  */
2036 public int bndIconLabelTextPosition(T=char) (NVGContext ctx, float x, float y, float w, float h, int iconid, float fontsize, const(T)[] label, int px, int py)
2037 if (isAnyCharType!T)
2038 {
2039   float[4] bounds;
2040   float pleft = BND_TEXT_RADIUS;
2041   if (label.length == 0) return -1;
2042   if (iconid >= 0) pleft += BND_ICON_SHEET_RES;
2043 
2044   if (!bndRealizeFont(ctx)) return -1;
2045 
2046   x += pleft;
2047   y += BND_WIDGET_HEIGHT-BND_TEXT_PAD_DOWN;
2048 
2049   ctx.fontSize(fontsize);
2050   ctx.textAlign(NVGTextAlign.H.Left, NVGTextAlign.V.Baseline);
2051 
2052   w -= BND_TEXT_RADIUS+pleft;
2053 
2054   float asc, desc, lh;
2055   static NVGTextRow!T[BND_MAX_ROWS] rows;
2056   auto rres = ctx.textBreakLines(label, w, rows[]);
2057   //{ import core.stdc.stdio : printf; printf("rlen=%u\n", cast(uint)rres.length); }
2058   if (rres.length == 0) return 0;
2059   ctx.textBoxBounds(x, y, w, label, bounds[]);
2060   ctx.textMetrics(&asc, &desc, &lh);
2061 
2062   // calculate vertical position
2063   int row = cast(int)bndClamp(cast(int)(cast(float)(py-bounds[1])/lh), 0, cast(int)rres.length-1);
2064   // search horizontal position
2065   static NVGGlyphPosition[BND_MAX_GLYPHS] glyphs;
2066   //int nglyphs = ctx.textGlyphPositions(x, y, rows[row].start, rows[row].end+1, glyphs.ptr, BND_MAX_GLYPHS);
2067   auto rglyphs = ctx.textGlyphPositions(x, y, rows[row].row!T, glyphs[]);
2068   int nglyphs = cast(int)rglyphs.length;
2069   int col, p = 0;
2070   for (col = 0; col < nglyphs && glyphs[col].x < px; ++col) p = cast(int)glyphs[col].strpos;
2071   // see if we should move one character further
2072   if (col > 0 && col < nglyphs && glyphs[col].x-px < px-glyphs[col-1].x) p = cast(int)glyphs[col].strpos;
2073   return p;
2074 }
2075 
2076 void bndCaretPosition(RT) (NVGContext ctx, float x, float y, float desc, float lineHeight, int caretpos, RT[] rows, int* cr, float* cx, float* cy)
2077 if (is(RT : NVGTextRow!CT, CT))
2078 {
2079   static NVGGlyphPosition[BND_MAX_GLYPHS] glyphs;
2080   usize r = 0;
2081   //for (r = 0; r < nrows && rows[r].end < caret; ++r) {}
2082   while (r < rows.length && rows[r].end < caretpos) ++r;
2083   if (cr !is null) *cr = cast(int)r;
2084   if (cx !is null) *cx = x;
2085   if (cy !is null) *cy = y-lineHeight-desc+r*lineHeight;
2086   if (rows.length == 0) return;
2087   if (cx !is null) *cx = rows[r].minx;
2088   //auto rglyphs = (rows[r].isChar ? ctx.textGlyphPositions(x, y, rows[r].row!char, glyphs[]) : ctx.textGlyphPositions(x, y, rows[r].row!dchar, glyphs[]));
2089   auto rglyphs = ctx.textGlyphPositions(x, y, rows[r].row, glyphs[]);
2090   foreach (immutable i; 0..rglyphs.length) {
2091     if (cx !is null) *cx = glyphs.ptr[i].x;
2092     if (glyphs.ptr[i].strpos == caretpos) break;
2093   }
2094 }
2095 
2096 /** Draw an optional icon specified by <iconid>, an optional label and
2097  * a caret with given fontsize and color within a widget box.
2098  *
2099  * if iconid is >= 0, an icon will be drawn and the labels remaining space will be adjusted.
2100  *
2101  * if label is not null, it will be drawn with the specified alignment, fontsize and color.
2102  *
2103  * cbegin must be >= 0 and <= strlen(text) and denotes the beginning of the caret
2104  *
2105  * cend must be >= cbegin and <= strlen(text) and denotes the end of the caret if cend < cbegin, then no caret will be drawn
2106  */
2107 public void bndIconLabelCaret(T=char) (NVGContext ctx, float x, float y, float w, float h, int iconid, NVGColor color, float fontsize, const(T)[] label, NVGColor caretcolor, int cbegin, int cend, NVGColor thinCaretColor=NVGColor.black)
2108 if (isAnyCharType!T)
2109 {
2110   float pleft = BND_TEXT_RADIUS;
2111   if (label.length == 0) return;
2112   if (iconid >= 0) {
2113     bndIcon(ctx, x+4, y+2, iconid);
2114     pleft += BND_ICON_SHEET_RES;
2115   }
2116 
2117   if (!bndRealizeFont(ctx)) return;
2118 
2119   x += pleft;
2120   y += BND_WIDGET_HEIGHT-BND_TEXT_PAD_DOWN;
2121 
2122   ctx.fontSize(fontsize);
2123   ctx.textAlign(NVGTextAlign.H.Left, NVGTextAlign.V.Baseline);
2124 
2125   w -= BND_TEXT_RADIUS+pleft;
2126 
2127   if (cend >= cbegin) {
2128     int c0r, c1r;
2129     float c0x, c0y, c1x, c1y;
2130     float desc, lh;
2131     static NVGTextRow!T[BND_MAX_ROWS] rows;
2132     auto rrows = ctx.textBreakLines(label[0..cend], w, rows[]);
2133     ctx.textMetrics(null, &desc, &lh);
2134 
2135     bndCaretPosition(ctx, x, y, desc, lh, cbegin, rrows, &c0r, &c0x, &c0y);
2136     bndCaretPosition(ctx, x, y, desc, lh, cend, rrows, &c1r, &c1x, &c1y);
2137 
2138     ctx.beginPath();
2139     if (cbegin == cend) {
2140       //ctx.fillColor(nvgRGBf(0.337, 0.502, 0.761));
2141       ctx.fillColor(thinCaretColor);
2142       //ctx.rect(c0x-1, c0y, 2, lh+1);
2143       ctx.rect(c0x, c0y, 1, lh+1);
2144     } else {
2145       ctx.fillColor(caretcolor);
2146       if (c0r == c1r) {
2147         ctx.rect(c0x-1, c0y, c1x-c0x+1, lh+1);
2148       } else {
2149         int blk = c1r-c0r-1;
2150         ctx.rect(c0x-1, c0y, x+w-c0x+1, lh+1);
2151         ctx.rect(x, c1y, c1x-x+1, lh+1);
2152         if (blk) ctx.rect(x, c0y+lh, w, blk*lh+1);
2153       }
2154     }
2155     ctx.fill();
2156   }
2157 
2158   ctx.beginPath();
2159   ctx.fillColor(color);
2160   ctx.textBox(x, y, w, label);
2161 }
2162 
2163 /// Draw a checkmark for an option box with the given upper left coordinates (ox, oy) with the specified color.
2164 public void bndCheck (NVGContext ctx, float ox, float oy, NVGColor color) {
2165   ctx.beginPath();
2166   ctx.strokeWidth(2);
2167   ctx.strokeColor(color);
2168   ctx.lineCap(NVGLineCap.Butt);
2169   ctx.lineJoin(NVGLineCap.Miter);
2170   ctx.moveTo(ox+4, oy+5);
2171   ctx.lineTo(ox+7, oy+8);
2172   ctx.lineTo(ox+14, oy+1);
2173   ctx.stroke();
2174 }
2175 
2176 /// Draw a checkmark for a radio with the given upper left coordinates (ox, oy) with the specified color.
2177 public void bndRadioCheck (NVGContext ctx, float ox, float oy, NVGColor color) {
2178   ctx.beginPath();
2179   ctx.fillColor(color);
2180   ctx.circle(ox+7, oy+7, 3);
2181   ctx.fill();
2182 }
2183 
2184 /// 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.
2185 public void bndArrow (NVGContext ctx, float x, float y, float s, NVGColor color) {
2186   ctx.beginPath();
2187   ctx.moveTo(x, y);
2188   ctx.lineTo(x-s, y+s);
2189   ctx.lineTo(x-s, y-s);
2190   ctx.closePath();
2191   ctx.fillColor(color);
2192   ctx.fill();
2193 }
2194 
2195 /// Draw an up/down arrow for a choice box with its center at (x, y) and size s
2196 public void bndUpDownArrow (NVGContext ctx, float x, float y, float s, NVGColor color) {
2197   float w;
2198   ctx.beginPath();
2199   w = 1.1f*s;
2200   ctx.moveTo(x, y-1);
2201   ctx.lineTo(x+0.5*w, y-s-1);
2202   ctx.lineTo(x+w, y-1);
2203   ctx.closePath();
2204   ctx.moveTo(x, y+1);
2205   ctx.lineTo(x+0.5*w, y+s+1);
2206   ctx.lineTo(x+w, y+1);
2207   ctx.closePath();
2208   ctx.fillColor(color);
2209   ctx.fill();
2210 }
2211 
2212 /// Draw a node down-arrow with its tip at (x, y) and size s
2213 public void bndNodeArrowDown (NVGContext ctx, float x, float y, float s, NVGColor color) {
2214   float w;
2215   ctx.beginPath();
2216   w = 1.0f*s;
2217   ctx.moveTo(x, y);
2218   ctx.lineTo(x+0.5*w, y-s);
2219   ctx.lineTo(x-0.5*w, y-s);
2220   ctx.closePath();
2221   ctx.fillColor(color);
2222   ctx.fill();
2223 }
2224 
2225 /** computes the bounds of the scrollbar handle from the scrollbar size and the handles offset and size.
2226  *
2227  * offset is in the range 0..1 and defines the position of the scroll handle
2228  *
2229  * size is in the range 0..1 and defines the size of the scroll handle
2230  */
2231 public void bndScrollHandleRect (float* x, float* y, float* w, float* h, float offset, float size) {
2232   assert(w !is null);
2233   assert(h !is null);
2234   size = bndClamp(size, 0, 1);
2235   offset = bndClamp(offset, 0, 1);
2236   if (*h > *w) {
2237     immutable float hs = bndMax(size*(*h), (*w)+1);
2238     if (y !is null) *y = (*y)+((*h)-hs)*offset;
2239     *h = hs;
2240   } else {
2241     immutable float ws = bndMax(size*(*w), (*h)-1);
2242     if (x !is null) *x = (*x)+((*w)-ws)*offset;
2243     *w = ws;
2244   }
2245 }
2246 
2247 /** computes the bounds of the scroll slider from the scrollbar size and the handles offset and size.
2248  *
2249  * offset is in the range 0..1 and defines the position of the scroll handle
2250  *
2251  * size is in the range 0..1 and defines the size of the scroll handle
2252  */
2253 public void bndScrollSliderRect (float* w, float* h, float offset, float size) {
2254   assert(w !is null);
2255   assert(h !is null);
2256   size = bndClamp(size, 0, 1);
2257   offset = bndClamp(offset, 0, 1);
2258   if (*h > *w) {
2259     immutable float hs = bndMax(size*(*h), (*w)+1);
2260     *h = ((*h)-hs)*offset+hs;
2261   } else {
2262     immutable float ws = bndMax(size*(*w), (*h)-1);
2263     *w = ((*w)-ws)*offset+ws;
2264   }
2265 }
2266 
2267 /** return the color of a node wire based on state
2268  *
2269  * BND_HOVER indicates selected state,
2270  *
2271  * BND_ACTIVE indicates dragged state
2272  */
2273 public NVGColor bndNodeWireColor (const(BNDnodeTheme)* theme, BNDwidgetState state) {
2274   switch (state) {
2275     default:
2276     case BND_DEFAULT: return nvgRGBf(0.5f, 0.5f, 0.5f);
2277     case BND_HOVER: return theme.wireSelectColor;
2278     case BND_ACTIVE: return theme.activeNodeColor;
2279   }
2280 }