diff --git a/example/demo.c b/example/demo.c index 3f2f9c9..d5632ce 100644 --- a/example/demo.c +++ b/example/demo.c @@ -818,6 +818,7 @@ void drawParagraph(struct NVGcontext* vg, float x, float y, float width, float h int nrows, i, nglyphs, j; float lineh; float caretx, px; + NVG_NOTUSED(height); nvgSave(vg); @@ -872,6 +873,15 @@ void drawParagraph(struct NVGcontext* vg, float x, float y, float width, float h start = rows[nrows-1].next; } + y += 10.0f; + + nvgFillColor(vg, nvgRGBA(0,0,0,220)); + nvgFontSize(vg, 12.0f); + nvgTextAlign(vg, NVG_ALIGN_LEFT|NVG_ALIGN_TOP); + nvgTextLineHeight(vg, 1.2f); + + nvgTextBox(vg, x,y, 150, "Hover your mouse over the text to see calculated caret position.", NULL); + nvgRestore(vg); } diff --git a/src/nanovg.c b/src/nanovg.c index 4a1cda9..bc2b2c0 100644 --- a/src/nanovg.c +++ b/src/nanovg.c @@ -66,6 +66,7 @@ struct NVGstate { struct NVGscissor scissor; float fontSize; float letterSpacing; + float lineHeight; float fontBlur; int textAlign; int fontId; @@ -290,13 +291,23 @@ struct NVGcolor nvgRGBf(float r, float g, float b) struct NVGcolor nvgRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { - struct NVGcolor color = {r/255.0f, g/255.0f, b/255.0f, a/255.0f}; + struct NVGcolor color; + // Use longer initialization to suppress warning. + color.r = r / 255.0f; + color.g = g / 255.0f; + color.b = b / 255.0f; + color.a = a / 255.0f; return color; } struct NVGcolor nvgRGBAf(float r, float g, float b, float a) { - struct NVGcolor color = {r, g, b, a}; + struct NVGcolor color; + // Use longer initialization to suppress warning. + color.r = r; + color.g = g; + color.b = b; + color.a = a; return color; } @@ -466,6 +477,7 @@ void nvgReset(struct NVGcontext* ctx) state->fontSize = 16.0f; state->letterSpacing = 0.0f; + state->lineHeight = 0.0f; state->fontBlur = 0.0f; state->textAlign = NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE; state->fontId = 0; @@ -574,7 +586,7 @@ int nvgCreateImage(struct NVGcontext* ctx, const char* filename) return image; } -int nvgCreateImageMem(struct NVGcontext* ctx, unsigned char* data, int ndata, int freeData) +int nvgCreateImageMem(struct NVGcontext* ctx, unsigned char* data, int ndata) { int w, h, n, image; unsigned char* img = stbi_load_from_memory(data, ndata, &w, &h, &n, 4); @@ -616,7 +628,7 @@ struct NVGpaint nvgLinearGradient(struct NVGcontext* ctx, struct NVGpaint p; float dx, dy, d; const float large = 1e5; - + NVG_NOTUSED(ctx); memset(&p, 0, sizeof(p)); // Calculate transform aligned to the line @@ -655,7 +667,7 @@ struct NVGpaint nvgRadialGradient(struct NVGcontext* ctx, struct NVGpaint p; float r = (inr+outr)*0.5f; float f = (outr-inr); - + NVG_NOTUSED(ctx); memset(&p, 0, sizeof(p)); nvg__xformIdentity(p.xform); @@ -680,7 +692,7 @@ struct NVGpaint nvgBoxGradient(struct NVGcontext* ctx, struct NVGcolor icol, struct NVGcolor ocol) { struct NVGpaint p; - + NVG_NOTUSED(ctx); memset(&p, 0, sizeof(p)); nvg__xformIdentity(p.xform); @@ -706,7 +718,7 @@ struct NVGpaint nvgImagePattern(struct NVGcontext* ctx, int image, int repeat) { struct NVGpaint p; - + NVG_NOTUSED(ctx); memset(&p, 0, sizeof(p)); nvg__xformRotate(p.xform, angle); @@ -1873,16 +1885,22 @@ void nvgFontSize(struct NVGcontext* ctx, float size) state->fontSize = size; } -void nvgLetterSpacing(struct NVGcontext* ctx, float spacing) +void nvgFontBlur(struct NVGcontext* ctx, float blur) +{ + struct NVGstate* state = nvg__getState(ctx); + state->fontBlur = blur; +} + +void nvgTextLetterSpacing(struct NVGcontext* ctx, float spacing) { struct NVGstate* state = nvg__getState(ctx); state->letterSpacing = spacing; } -void nvgFontBlur(struct NVGcontext* ctx, float blur) +void nvgTextLineHeight(struct NVGcontext* ctx, float lineHeight) { struct NVGstate* state = nvg__getState(ctx); - state->fontBlur = blur; + state->lineHeight = lineHeight; } void nvgTextAlign(struct NVGcontext* ctx, int align) @@ -1984,6 +2002,41 @@ float nvgText(struct NVGcontext* ctx, float x, float y, const char* string, cons return iter.x; } +float nvgTextBox(struct NVGcontext* ctx, float x, float y, float width, const char* string, const char* end) +{ + struct NVGstate* state = nvg__getState(ctx); + struct NVGtextRow rows[2]; + int nrows = 0, i; + int oldAlign = state->textAlign; + int haling = state->textAlign & (NVG_ALIGN_LEFT | NVG_ALIGN_CENTER | NVG_ALIGN_RIGHT); + int valign = state->textAlign & (NVG_ALIGN_TOP | NVG_ALIGN_MIDDLE | NVG_ALIGN_BOTTOM | NVG_ALIGN_BASELINE); + float lineh = 0; + + if (state->fontId == FONS_INVALID) return x; + + nvgTextMetrics(ctx, NULL, NULL, &lineh); + + state->textAlign = NVG_ALIGN_LEFT | valign; + + while ((nrows = nvgTextBreakLines(ctx, string, end, width, rows, 2))) { + for (i = 0; i < nrows; i++) { + struct NVGtextRow* row = &rows[i]; + if (haling & NVG_ALIGN_LEFT) + nvgText(ctx, x, y, row->start, row->end); + else if (haling & NVG_ALIGN_CENTER) + nvgText(ctx, x + width*0.5f - row->width*0.5f, y, row->start, row->end); + else if (haling & NVG_ALIGN_RIGHT) + nvgText(ctx, x + width - row->width, y, row->start, row->end); + y += lineh * state->lineHeight; + } + string = rows[nrows-1].next; + } + + state->textAlign = oldAlign; + + return 0; // TODO +} + int nvgTextGlyphPositions(struct NVGcontext* ctx, const char* string, const char* end, float x, float y, struct NVGglyphPosition* positions, int maxPositions) { struct NVGstate* state = nvg__getState(ctx); diff --git a/src/nanovg.h b/src/nanovg.h index 1c603ea..7a62230 100644 --- a/src/nanovg.h +++ b/src/nanovg.h @@ -27,20 +27,16 @@ extern "C" { struct NVGcontext; -struct NVGcolor -{ - union - { +struct NVGcolor { + union { float rgba[4]; - struct - { + struct { float r,g,b,a; }; }; }; -struct NVGpaint -{ +struct NVGpaint { float xform[6]; float extent[2]; float radius; @@ -91,6 +87,19 @@ enum NVGalpha { NVG_PREMULTIPLIED_ALPHA, }; +struct NVGglyphPosition { + const char* str; // Position of the glyph in the input string. + float x; // The x- coordinate of the position of the glyph . +}; + +struct NVGtextRow { + const char* start; // Pointer to the input text where the row starts. + const char* end; // Pointer to the input text where the row ends (one past the last character). + const char* next; // Pointer to the beginning of the next row. + float width; // Width of the row. +}; + + // Begin drawing a new frame // Calls to nanovg drawing API should be wrapped in nvgBeginFrame() & nvgEndFrame() // nvgBeginFrame() defines the size of the window to render to in relation currently @@ -243,9 +252,9 @@ void nvgScale(struct NVGcontext* ctx, float x, float y); // Returns handle to the image. int nvgCreateImage(struct NVGcontext* ctx, const char* filename); -// Creates image by loading it from the specified memory chunk. +// Creates image by loading it from the specified chunk of memory. // Returns handle to the image. -int nvgCreateImageMem(struct NVGcontext* ctx, unsigned char* data, int ndata, int freeData); +int nvgCreateImageMem(struct NVGcontext* ctx, unsigned char* data, int ndata); // Creates image from specified image data. // Returns handle to the image. @@ -394,12 +403,15 @@ int nvgFindFont(struct NVGcontext* ctx, const char* name); // Sets the font size of current text style. void nvgFontSize(struct NVGcontext* ctx, float size); -// Sets the letter spacing of current text style. -void nvgLetterSpacing(struct NVGcontext* ctx, float spacing); - // Sets the blur of current text style. void nvgFontBlur(struct NVGcontext* ctx, float blur); +// Sets the letter spacing of current text style. +void nvgTextLetterSpacing(struct NVGcontext* ctx, float spacing); + +// Sets the proportional line height of current text style. The line height is specified as multiple of font size. +void nvgTextLineHeight(struct NVGcontext* ctx, float lineHeight); + // Sets the text align of current text style, see NVGaling for options. void nvgTextAlign(struct NVGcontext* ctx, int align); @@ -412,6 +424,11 @@ void nvgFontFace(struct NVGcontext* ctx, const char* font); // Draws text string at specified location. If end is specified only the sub-string up to the end is drawn. float nvgText(struct NVGcontext* ctx, float x, float y, const char* string, const char* end); +// Draws multi-line text string at specified location wrapped at the specified width. If end is specified only the sub-string up to the end is drawn. +// White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered. +// Words longer than the max width are slit at nearest character (i.e. no hyphenation). +float nvgTextBox(struct NVGcontext* ctx, float x, float y, float width, const char* string, const char* end); + // Measures the specified text string. Parameter bounds should be a pointer to float[4] if // the bounding box of the text should be returned. Returns the width of the measured text. // Current transform does not affect the measured values. @@ -421,18 +438,12 @@ float nvgTextBounds(struct NVGcontext* ctx, const char* string, const char* end, // Current transform does not affect the measured values. void nvgTextMetrics(struct NVGcontext* ctx, float* ascender, float* descender, float* lineh); -struct NVGglyphPosition { - const char* str; - float x; -}; +// Calculates the glyph x positions of the specified text. If end is specified only the sub-string will be used. int nvgTextGlyphPositions(struct NVGcontext* ctx, const char* string, const char* end, float x, float y, struct NVGglyphPosition* positions, int maxPositions); -struct NVGtextRow { - const char* start; - const char* end; - const char* next; - float width; -}; +// Breaks the specified text into lines. If end is specified only the sub-string will be used. +// White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered. +// Words longer than the max width are slit at nearest character (i.e. no hyphenation). int nvgTextBreakLines(struct NVGcontext* ctx, const char* string, const char* end, float maxRowWidth, struct NVGtextRow* rows, int maxRows); //