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