|
|
@@ -802,6 +802,13 @@ BND_EXPORT void bndRadioButton(NVGcontext *ctx, |
|
|
|
float x, float y, float w, float h, int flags, BNDwidgetState state, |
|
|
|
int iconid, const char *label); |
|
|
|
|
|
|
|
|
|
|
|
// Calculate the corresponding text position for given coordinates px/py |
|
|
|
// in a text field. |
|
|
|
// See bndTextField for more info. |
|
|
|
BND_EXPORT int bndTextFieldTextPosition(NVGcontext *ctx, float x, float y, float w, float h, |
|
|
|
int iconid, const char *text, int px, int py); |
|
|
|
|
|
|
|
// Draw a text field with its lower left origin at (x,y) and size of (w,h), |
|
|
|
// where flags is one or multiple flags from BNDcornerFlags and state denotes |
|
|
|
// the widgets current UI state. |
|
|
@@ -1044,6 +1051,12 @@ BND_EXPORT void bndIconLabelValue(NVGcontext *ctx, float x, float y, float w, fl |
|
|
|
BND_EXPORT void bndNodeIconLabel(NVGcontext *ctx, float x, float y, float w, float h, |
|
|
|
int iconid, NVGcolor color, NVGcolor shadowColor, int align, |
|
|
|
float fontsize, const char *label); |
|
|
|
|
|
|
|
// Calculate the corresponding text position for given coordinates px/py |
|
|
|
// in an iconLabel. |
|
|
|
// See bndIconLabelCaret for more info. |
|
|
|
BND_EXPORT int bndIconLabelTextPosition(NVGcontext *ctx, float x, float y, float w, float h, |
|
|
|
int iconid, float fontsize, const char *label, int px, int py); |
|
|
|
|
|
|
|
// Draw an optional icon specified by <iconid>, an optional label and |
|
|
|
// a caret with given fontsize and color within a widget box. |
|
|
@@ -1208,6 +1221,9 @@ static double bnd_fmax ( double a, double b ) |
|
|
|
// max glyphs for position testing |
|
|
|
#define BND_MAX_GLYPHS 1024 |
|
|
|
|
|
|
|
// max rows for position testing |
|
|
|
#define BND_MAX_ROWS 32 |
|
|
|
|
|
|
|
// text distance from bottom |
|
|
|
#define BND_TEXT_PAD_DOWN 7 |
|
|
|
|
|
|
@@ -1445,6 +1461,12 @@ void bndRadioButton(NVGcontext *ctx, |
|
|
|
BND_LABEL_FONT_SIZE, label, NULL); |
|
|
|
} |
|
|
|
|
|
|
|
int bndTextFieldTextPosition(NVGcontext *ctx, float x, float y, float w, float h, |
|
|
|
int iconid, const char *text, int px, int py) { |
|
|
|
return bndIconLabelTextPosition(ctx, x, y, w, h, |
|
|
|
iconid, BND_LABEL_FONT_SIZE, text, px, py); |
|
|
|
} |
|
|
|
|
|
|
|
void bndTextField(NVGcontext *ctx, |
|
|
|
float x, float y, float w, float h, int flags, BNDwidgetState state, |
|
|
|
int iconid, const char *text, int cbegin, int cend) { |
|
|
@@ -2131,17 +2153,17 @@ void bndIconLabelValue(NVGcontext *ctx, float x, float y, float w, float h, |
|
|
|
+ nvgTextBounds(ctx, 1, 1, value, NULL, NULL); |
|
|
|
x += ((w-BND_PAD_RIGHT-pleft)-width)*0.5f; |
|
|
|
} |
|
|
|
y += h-BND_TEXT_PAD_DOWN; |
|
|
|
y += BND_WIDGET_HEIGHT-BND_TEXT_PAD_DOWN; |
|
|
|
nvgText(ctx, x, y, label, NULL); |
|
|
|
x += label_width; |
|
|
|
nvgText(ctx, x, y, BND_LABEL_SEPARATOR, NULL); |
|
|
|
x += sep_width; |
|
|
|
nvgText(ctx, x, y, value, NULL); |
|
|
|
nvgText(ctx, x, y, value, NULL); |
|
|
|
} else { |
|
|
|
nvgTextAlign(ctx, |
|
|
|
(align==BND_LEFT)?(NVG_ALIGN_LEFT|NVG_ALIGN_BASELINE): |
|
|
|
(NVG_ALIGN_CENTER|NVG_ALIGN_BASELINE)); |
|
|
|
nvgTextBox(ctx,x+pleft,y+h-BND_TEXT_PAD_DOWN, |
|
|
|
nvgTextBox(ctx,x+pleft,y+BND_WIDGET_HEIGHT-BND_TEXT_PAD_DOWN, |
|
|
|
w-BND_PAD_RIGHT-pleft,label, NULL); |
|
|
|
} |
|
|
|
} else if (iconid >= 0) { |
|
|
@@ -2171,10 +2193,70 @@ void bndNodeIconLabel(NVGcontext *ctx, float x, float y, float w, float h, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
int bndIconLabelTextPosition(NVGcontext *ctx, float x, float y, float w, float h, |
|
|
|
int iconid, float fontsize, const char *label, int px, int py) { |
|
|
|
float bounds[4]; |
|
|
|
float pleft = BND_TEXT_RADIUS; |
|
|
|
if (!label) return -1; |
|
|
|
if (iconid >= 0) |
|
|
|
pleft += BND_ICON_SHEET_RES; |
|
|
|
|
|
|
|
if (bnd_font < 0) return -1; |
|
|
|
|
|
|
|
x += pleft; |
|
|
|
y += BND_WIDGET_HEIGHT - BND_TEXT_PAD_DOWN; |
|
|
|
|
|
|
|
nvgFontFaceId(ctx, bnd_font); |
|
|
|
nvgFontSize(ctx, fontsize); |
|
|
|
nvgTextAlign(ctx, NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE); |
|
|
|
|
|
|
|
w -= BND_TEXT_RADIUS + pleft; |
|
|
|
|
|
|
|
float asc, desc, lh; |
|
|
|
static NVGtextRow rows[BND_MAX_ROWS]; |
|
|
|
int nrows = nvgTextBreakLines( |
|
|
|
ctx, label, NULL, w, rows, BND_MAX_ROWS); |
|
|
|
if (nrows == 0) return 0; |
|
|
|
nvgTextBoxBounds(ctx, x, y, w, label, NULL, bounds); |
|
|
|
nvgTextMetrics(ctx, &asc, &desc, &lh); |
|
|
|
|
|
|
|
// calculate vertical position |
|
|
|
int row = bnd_clamp((int)((float)(py - bounds[1]) / lh), 0, nrows - 1); |
|
|
|
// search horizontal position |
|
|
|
static NVGglyphPosition glyphs[BND_MAX_GLYPHS]; |
|
|
|
int nglyphs = nvgTextGlyphPositions( |
|
|
|
ctx, x, y, rows[row].start, rows[row].end + 1, glyphs, BND_MAX_GLYPHS); |
|
|
|
int col, p = 0; |
|
|
|
for (col = 0; col < nglyphs && glyphs[col].x < px; ++col) |
|
|
|
p = glyphs[col].str - label; |
|
|
|
// see if we should move one character further |
|
|
|
if (col > 0 && col < nglyphs && glyphs[col].x - px < px - glyphs[col - 1].x) |
|
|
|
p = glyphs[col].str - label; |
|
|
|
return p; |
|
|
|
} |
|
|
|
|
|
|
|
static void bndCaretPosition(NVGcontext *ctx, float x, float y, |
|
|
|
float desc, float lineHeight, const char *caret, NVGtextRow *rows,int nrows, |
|
|
|
int *cr, float *cx, float *cy) { |
|
|
|
static NVGglyphPosition glyphs[BND_MAX_GLYPHS]; |
|
|
|
int r,nglyphs; |
|
|
|
for (r=0; r < nrows && rows[r].end < caret; ++r); |
|
|
|
*cr = r; |
|
|
|
*cx = x; |
|
|
|
*cy = y-lineHeight-desc + r*lineHeight; |
|
|
|
if (nrows == 0) return; |
|
|
|
*cx = rows[r].minx; |
|
|
|
nglyphs = nvgTextGlyphPositions( |
|
|
|
ctx, x, y, rows[r].start, rows[r].end+1, glyphs, BND_MAX_GLYPHS); |
|
|
|
for (int i=0; i < nglyphs; ++i) { |
|
|
|
*cx=glyphs[i].x; |
|
|
|
if (glyphs[i].str == caret) break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void bndIconLabelCaret(NVGcontext *ctx, float x, float y, float w, float h, |
|
|
|
int iconid, NVGcolor color, float fontsize, const char *label, |
|
|
|
NVGcolor caretcolor, int cbegin, int cend) { |
|
|
|
float bounds[4]; |
|
|
|
float pleft = BND_TEXT_RADIUS; |
|
|
|
if (!label) return; |
|
|
|
if (iconid >= 0) { |
|
|
@@ -2194,70 +2276,37 @@ void bndIconLabelCaret(NVGcontext *ctx, float x, float y, float w, float h, |
|
|
|
w -= BND_TEXT_RADIUS+pleft; |
|
|
|
|
|
|
|
if (cend >= cbegin) { |
|
|
|
#if 1 |
|
|
|
float c0,c1; |
|
|
|
const char *cb;const char *ce; |
|
|
|
static NVGglyphPosition glyphs[BND_MAX_GLYPHS]; |
|
|
|
int nglyphs = nvgTextGlyphPositions( |
|
|
|
ctx, x, y, label, label+cend+1, glyphs, BND_MAX_GLYPHS); |
|
|
|
c0=glyphs[0].x; |
|
|
|
c1=glyphs[nglyphs-1].x; |
|
|
|
cb = label+cbegin; ce = label+cend; |
|
|
|
// TODO: this is slow |
|
|
|
for (int i=0; i < nglyphs; ++i) { |
|
|
|
if (glyphs[i].str == cb) |
|
|
|
c0 = glyphs[i].x; |
|
|
|
if (glyphs[i].str == ce) |
|
|
|
c1 = glyphs[i].x; |
|
|
|
} |
|
|
|
int c0r,c1r; |
|
|
|
float c0x,c0y,c1x,c1y; |
|
|
|
float desc,lh; |
|
|
|
static NVGtextRow rows[BND_MAX_ROWS]; |
|
|
|
int nrows = nvgTextBreakLines( |
|
|
|
ctx, label, label+cend+1, w, rows, BND_MAX_ROWS); |
|
|
|
nvgTextMetrics(ctx, NULL, &desc, &lh); |
|
|
|
|
|
|
|
bndCaretPosition(ctx, x, y, desc, lh, label+cbegin, |
|
|
|
rows, nrows, &c0r, &c0x, &c0y); |
|
|
|
bndCaretPosition(ctx, x, y, desc, lh, label+cend, |
|
|
|
rows, nrows, &c1r, &c1x, &c1y); |
|
|
|
|
|
|
|
nvgTextBounds(ctx,x,y,label,NULL, bounds); |
|
|
|
nvgBeginPath(ctx); |
|
|
|
if (cbegin == cend) { |
|
|
|
nvgFillColor(ctx, nvgRGBf(0.337,0.502,0.761)); |
|
|
|
nvgRect(ctx, c0-1, bounds[1], 2, bounds[3]-bounds[1]); |
|
|
|
} else { |
|
|
|
nvgFillColor(ctx, caretcolor); |
|
|
|
nvgRect(ctx, c0-1, bounds[1], c1-c0+1, bounds[3]-bounds[1]); |
|
|
|
} |
|
|
|
nvgFill(ctx); |
|
|
|
#else |
|
|
|
float c0,c1; |
|
|
|
const char *cb; |
|
|
|
const char *ce; |
|
|
|
const char *line; |
|
|
|
int numlines; |
|
|
|
cb = label+cbegin; ce = label+cend; |
|
|
|
line = label; |
|
|
|
|
|
|
|
NVGtextRow rows[2]; |
|
|
|
numlines = nvgTextBreakLines(ctx, line, NULL, w, rows, 2); |
|
|
|
|
|
|
|
/* |
|
|
|
int nglyphs = nvgTextGlyphPositions( |
|
|
|
ctx, x, y, label, label+cend+1, glyphs, BND_MAX_GLYPHS); |
|
|
|
c0=glyphs[0].x; |
|
|
|
c1=glyphs[nglyphs-1].x; |
|
|
|
// TODO: this is slow |
|
|
|
for (int i=0; i < nglyphs; ++i) { |
|
|
|
if (glyphs[i].str == cb) |
|
|
|
c0 = glyphs[i].x; |
|
|
|
if (glyphs[i].str == ce) |
|
|
|
c1 = glyphs[i].x; |
|
|
|
} |
|
|
|
|
|
|
|
nvgTextBounds(ctx,x,y,label,NULL, bounds); |
|
|
|
nvgBeginPath(ctx); |
|
|
|
if (cbegin == cend) { |
|
|
|
nvgFillColor(ctx, nvgRGBf(0.337,0.502,0.761)); |
|
|
|
nvgRect(ctx, c0-1, bounds[1], 2, bounds[3]-bounds[1]); |
|
|
|
nvgRect(ctx, c0x-1, c0y, 2, lh+1); |
|
|
|
} else { |
|
|
|
nvgFillColor(ctx, caretcolor); |
|
|
|
nvgRect(ctx, c0-1, bounds[1], c1-c0+1, bounds[3]-bounds[1]); |
|
|
|
if (c0r == c1r) { |
|
|
|
nvgRect(ctx, c0x-1, c0y, c1x-c0x+1, lh+1); |
|
|
|
} else { |
|
|
|
int blk=c1r-c0r-1; |
|
|
|
nvgRect(ctx, c0x-1, c0y, x+w-c0x+1, lh+1); |
|
|
|
nvgRect(ctx, x, c1y, c1x-x+1, lh+1); |
|
|
|
|
|
|
|
if (blk) |
|
|
|
nvgRect(ctx, x, c0y+lh, w, blk*lh+1); |
|
|
|
} |
|
|
|
} |
|
|
|
nvgFill(ctx); |
|
|
|
*/ |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
nvgBeginPath(ctx); |
|
|
|