Exemple #1
0
size_t NvgFont::get_cursor_location(const std::string & text, float fontSize, int xCoord) const
{
    std::vector<NVGglyphPosition> positions(text.size());
    nvgFontSize(nvg, fontSize);
    nvgFontFaceId(nvg, id);
    nvgTextAlign(nvg, NVG_ALIGN_LEFT | NVG_ALIGN_TOP);
    positions.resize(nvgTextGlyphPositions(nvg, 0, 0, text.data(), text.data() + (int) text.size(), positions.data(), (int) positions.size()));
    for (size_t i = 0; i<positions.size(); ++i)
    {
        if(xCoord < positions[i].maxx)
            return i;
    }
    return positions.size();
}
int Font::getCursorPosition(const std::string & text, float fontSize,
		int xCoord) const {
	std::vector<NVGglyphPosition> positions(text.size());
	nvgFontSize(nvg, fontSize);
	nvgFontFaceId(nvg, handle);
	nvgTextAlign(nvg, NVG_ALIGN_LEFT | NVG_ALIGN_TOP);
	positions.resize(
			nvgTextGlyphPositions(nvg, 0, 0, text.data(),
					text.data() + text.size(), positions.data(),
					(int) positions.size()));
	for (size_t i = 0; i < positions.size(); ++i) {
		if (xCoord < positions[i].maxx) {
			return static_cast<int>(i);
		}
	}
	return static_cast<int>(positions.size());
}
Exemple #3
0
void Caret::updatePosFromIdx(NVGcontext *ctx) {
    
    float lineh;
    nvgTextMetrics(ctx, nullptr, nullptr, &lineh);
    const int maxGlyphs = 1024;
    NVGglyphPosition glyphs[maxGlyphs];
    const std::string& textLine = mConsole->mBuffer[mIdx.y()];
    float textBound[4];

    nvgTextBounds(ctx, 0, 0, textLine.c_str(), nullptr, textBound);
    int nglyphs = nvgTextGlyphPositions(ctx, 0, 0, textLine.c_str(),
            nullptr, glyphs, maxGlyphs);

    //update carete position now
    mPos.y() = mIdx.y() * lineh;
    mPos.x() = cursorIndex2Position(mIdx.x(), textBound[2], glyphs, nglyphs);
}
Exemple #4
0
void Caret::onClick(NVGcontext *ctx, float lineh, Vector2i clickPos){
    if (clickPos.x() > -1) {
        mIdx.y() = (int) clickPos.y()/lineh;
        //std::cout << "mPos = " << mConsole->mPos.x() << "," << mConsole->mPos.y() << std::endl;

        if(mIdx.y() < (int)mConsole->mBuffer.size()){
            //std::cout << mBuffer.at(mCursorPosY)<< std::endl;
            double time = glfwGetTime();
            if (time - mLastClick < 0.25) {
                /* Double-click: select a line */
                int linew = mConsole->mSize.x();
                mSelectionIdx = Vector2i(0,(int) clickPos.y()/lineh); 
                mSelectionPos = Vector2i(0,mSelectionIdx.y()*lineh);
                mIdx = Vector2i(mConsole->mBuffer[mSelectionIdx.y()].size(), mSelectionIdx.y());
                mPos = Vector2i(linew, mSelectionPos.y());
                mSelectionState = true;
                std::cout << "Sel : " << mSelectionPos.x() << "," << mSelectionPos.y() << std::endl;
                std::cout << "Pos : " << mPos.x() << "," << mPos.y() << std::endl;
            }
            else { 
                const int maxGlyphs = 1024;
                NVGglyphPosition glyphs[maxGlyphs];
                const std::string& textLine = mConsole->mBuffer[mIdx.y()];
                float textBound[4];

                nvgTextBounds(ctx, 0, 0, textLine.c_str(), nullptr, textBound);
                int nglyphs = nvgTextGlyphPositions(ctx, 0, 0, textLine.c_str(),
                        nullptr, glyphs, maxGlyphs);

                mIdx.x() = position2CursorIndex(clickPos.x(), textBound[2], glyphs, nglyphs);
         
                //update carete position now
                mPos.y() = mIdx.y() * lineh;
                mPos.x() = cursorIndex2Position(mIdx.x(), textBound[2], glyphs, nglyphs);
            }
            mLastClick = time;
        }
    }
}
Exemple #5
0
void drawParagraph(struct NVGcontext* vg, float x, float y, float width, float height, float mx, float my)
{
	struct NVGtextRow rows[3];
	struct NVGglyphPosition glyphs[100];
	const char* text = "This is longer chunk of text.\n  \n  Would have used lorem ipsum but she    was busy jumping over the lazy dog with the fox and all the men who came to the aid of the party.";
	const char* start;
	const char* end;
	int nrows, i, nglyphs, j, lnum = 0;
	float lineh;
	float caretx, px;
	float bounds[4];
	float gx = 0.0f, gy = 0.0f;
	int gutter = 0;
	NVG_NOTUSED(height);

	nvgSave(vg);

	nvgFontSize(vg, 18.0f);
	nvgFontFace(vg, "sans");
	nvgTextAlign(vg, NVG_ALIGN_LEFT|NVG_ALIGN_TOP);
	nvgTextMetrics(vg, NULL, NULL, &lineh);

	// The text break API can be used to fill a large buffer of rows,
	// or to iterate over the text just few lines (or just one) at a time.
	// The "next" variable of the last returned item tells where to continue.
	start = text;
	end = text + strlen(text);
	for (nrows = nvgTextBreakLines(vg, start, end, width, rows, 3); 0 != nrows; nrows = nvgTextBreakLines(vg, start, end, width, rows, 3) )
	{
		for (i = 0; i < nrows; i++) {
			struct NVGtextRow* row = &rows[i];
			int hit = mx > x && mx < (x+width) && my >= y && my < (y+lineh);

			nvgBeginPath(vg);
			nvgFillColor(vg, nvgRGBA(255,255,255,hit?64:8) );
			nvgRect(vg, x, y, row->width, lineh);
			nvgFill(vg);

			nvgFillColor(vg, nvgRGBA(255,255,255,255) );
			nvgText(vg, x, y, row->start, row->end);

			if (hit) {
				caretx = (mx < x+row->width/2) ? x : x+row->width;
				px = x;
				nglyphs = nvgTextGlyphPositions(vg, x, y, row->start, row->end, glyphs, 100);
				for (j = 0; j < nglyphs; j++) {
					float x0 = glyphs[j].x;
					float x1 = (j+1 < nglyphs) ? glyphs[j+1].x : x+row->width;
					float tgx = x0 * 0.3f + x1 * 0.7f;
					if (mx >= px && mx < tgx)
						caretx = glyphs[j].x;
					px = tgx;
				}
				nvgBeginPath(vg);
				nvgFillColor(vg, nvgRGBA(255,192,0,255) );
				nvgRect(vg, caretx, y, 1, lineh);
				nvgFill(vg);

				gutter = lnum+1;
				gx = x - 10;
				gy = y + lineh/2;
			}
			lnum++;
			y += lineh;
		}
		// Keep going...
		start = rows[nrows-1].next;
	}

	if (gutter)
	{
		char txt[16];
		bx::snprintf(txt, sizeof(txt), "%d", gutter);
		nvgFontSize(vg, 13.0f);
		nvgTextAlign(vg, NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE);

		nvgTextBounds(vg, gx,gy, txt, NULL, bounds);

		nvgBeginPath(vg);
		nvgFillColor(vg, nvgRGBA(255,192,0,255) );
		nvgRoundedRect(vg
			, bx::fround(bounds[0])-4.0f
			, bx::fround(bounds[1])-2.0f
			, bx::fround(bounds[2]-bounds[0])+8.0f
			, bx::fround(bounds[3]-bounds[1])+4.0f
			, (bx::fround(bounds[3]-bounds[1])+4.0f)/2.0f-1.0f
			);
		nvgFill(vg);

		nvgFillColor(vg, nvgRGBA(32,32,32,255) );
		nvgText(vg, gx,gy, txt, NULL);
	}

	y += 20.0f;

	nvgFontSize(vg, 13.0f);
	nvgTextAlign(vg, NVG_ALIGN_LEFT|NVG_ALIGN_TOP);
	nvgTextLineHeight(vg, 1.2f);

	nvgTextBoxBounds(vg, x,y, 150, "Hover your mouse over the text to see calculated caret position.", NULL, bounds);
	nvgBeginPath(vg);
	nvgFillColor(vg, nvgRGBA(220,220,220,255) );
	nvgRoundedRect(vg
		, bx::fround(bounds[0]-2.0f)
		, bx::fround(bounds[1]-2.0f)
		, bx::fround(bounds[2]-bounds[0])+4.0f
		, bx::fround(bounds[3]-bounds[1])+4.0f
		, 3.0f
		);
	px = float( (int)( (bounds[2]+bounds[0])/2) );
	nvgMoveTo(vg, px,bounds[1] - 10);
	nvgLineTo(vg, px+7,bounds[1]+1);
	nvgLineTo(vg, px-7,bounds[1]+1);
	nvgFill(vg);

	nvgFillColor(vg, nvgRGBA(0,0,0,220) );
	nvgTextBox(vg, x,y, 150, "Hover your mouse over the text to see calculated caret position.", NULL);

	nvgRestore(vg);
}
Exemple #6
0
void TextBox::draw(NVGcontext* ctx) {
    Widget::draw(ctx);

    NVGpaint bg = nvgBoxGradient(ctx,
        mPos.x() + 1, mPos.y() + 1 + 1.0f, mSize.x() - 2, mSize.y() - 2,
        3, 4, Color(255, 32), Color(32, 32)); 
    NVGpaint fg1 = nvgBoxGradient(ctx,
        mPos.x() + 1, mPos.y() + 1 + 1.0f, mSize.x() - 2, mSize.y() - 2,
        3, 4, Color(150, 32), Color(32, 32));
    NVGpaint fg2 = nvgBoxGradient(ctx, 
        mPos.x() + 1, mPos.y() + 1 + 1.0f, mSize.x() - 2, mSize.y() - 2,
        3, 4, nvgRGBA(255, 0, 0, 100), nvgRGBA(255, 0, 0, 50));

    nvgBeginPath(ctx);
    nvgRoundedRect(ctx, mPos.x() + 1, mPos.y() + 1 + 1.0f, mSize.x() - 2,
                   mSize.y() - 2, 3);

    if(mEditable && focused())
        mValidFormat ? nvgFillPaint(ctx, fg1) : nvgFillPaint(ctx, fg2);
    else
        nvgFillPaint(ctx, bg);

    nvgFill(ctx);

    nvgBeginPath(ctx);
    nvgRoundedRect(ctx, mPos.x() + 0.5f, mPos.y() + 0.5f, mSize.x() - 1,
                   mSize.y() - 1, 2.5f);
    nvgStrokeColor(ctx, Color(0, 48));
    nvgStroke(ctx);

    nvgFontSize(ctx, fontSize());
    nvgFontFace(ctx, "sans");
    Vector2i drawPos(mPos.x(), mPos.y() + mSize.y() * 0.5f + 1);

    float xSpacing = mSize.y() * 0.3f;

    float unitWidth = 0;

    if (mUnitsImage > 0) {
        int w, h;
        nvgImageSize(ctx, mUnitsImage, &w, &h);
        float unitHeight = mSize.y() * 0.4f;
        unitWidth = w * unitHeight / h;
        NVGpaint imgPaint = nvgImagePattern(
            ctx, mPos.x() + mSize.x() - xSpacing - unitWidth,
            drawPos.y() - unitHeight * 0.5f, unitWidth, unitHeight, 0,
            mUnitsImage, mEnabled ? 0.7f : 0.35f);
        nvgBeginPath(ctx);
        nvgRect(ctx, mPos.x() + mSize.x() - xSpacing - unitWidth,
                drawPos.y() - unitHeight * 0.5f, unitWidth, unitHeight);
        nvgFillPaint(ctx, imgPaint);
        nvgFill(ctx);
        unitWidth += 2;
    } else if (!mUnits.empty()) {
        unitWidth = nvgTextBounds(ctx, 0, 0, mUnits.c_str(), nullptr, nullptr);
        nvgFillColor(ctx, Color(255, mEnabled ? 64 : 32));
        nvgTextAlign(ctx, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE);
        nvgText(ctx, mPos.x() + mSize.x() - xSpacing, drawPos.y(),
                mUnits.c_str(), nullptr);
        unitWidth += 2;
    }

    switch (mAlignment) {
        case Alignment::Left:
            nvgTextAlign(ctx, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
            drawPos.x() += xSpacing;
            break;
        case Alignment::Right:
            nvgTextAlign(ctx, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE);
            drawPos.x() += mSize.x() - unitWidth - xSpacing;
            break;
        case Alignment::Center:
            nvgTextAlign(ctx, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
            drawPos.x() += mSize.x() * 0.5f;
            break;
    }

    nvgFontSize(ctx, fontSize());
    nvgFillColor(ctx,
                 mEnabled ? mTheme->mTextColor : mTheme->mDisabledTextColor);

    // clip visible text area
    float clipX = mPos.x() + xSpacing - 1.0f;
    float clipY = mPos.y() + 1.0f;
    float clipWidth = mSize.x() - unitWidth - 2 * xSpacing + 2.0f;
    float clipHeight = mSize.y() - 3.0f;
    nvgScissor(ctx, clipX, clipY, clipWidth, clipHeight);

    Vector2i oldDrawPos(drawPos);
    drawPos.x() += mTextOffset;

    if (mCommitted) {
        nvgText(ctx, drawPos.x(), drawPos.y(), mValue.c_str(), nullptr);
    } else {
        const int maxGlyphs = 1024;
        NVGglyphPosition glyphs[maxGlyphs];
        float textBound[4];
        nvgTextBounds(ctx, drawPos.x(), drawPos.y(), mValueTemp.c_str(),
                      nullptr, textBound);
        float lineh = textBound[3] - textBound[1];

        // find cursor positions
        int nglyphs =
            nvgTextGlyphPositions(ctx, drawPos.x(), drawPos.y(),
                                  mValueTemp.c_str(), nullptr, glyphs, maxGlyphs);
        updateCursor(ctx, textBound[2], glyphs, nglyphs);

        // compute text offset
        int prevCPos = mCursorPos > 0 ? mCursorPos - 1 : 0;
        int nextCPos = mCursorPos < nglyphs ? mCursorPos + 1 : nglyphs;
        float prevCX = cursorIndex2Position(prevCPos, textBound[2], glyphs, nglyphs);
        float nextCX = cursorIndex2Position(nextCPos, textBound[2], glyphs, nglyphs);

        if (nextCX > clipX + clipWidth)
            mTextOffset -= nextCX - (clipX + clipWidth) + 1;
        if (prevCX < clipX)
            mTextOffset += clipX - prevCX + 1;

        drawPos.x() = oldDrawPos.x() + mTextOffset;

        // draw text with offset
        nvgText(ctx, drawPos.x(), drawPos.y(), mValueTemp.c_str(), nullptr);
        nvgTextBounds(ctx, drawPos.x(), drawPos.y(), mValueTemp.c_str(),
                      nullptr, textBound);

        // recompute cursor positions
        nglyphs = nvgTextGlyphPositions(ctx, drawPos.x(), drawPos.y(),
                mValueTemp.c_str(), nullptr, glyphs, maxGlyphs);

        if (mCursorPos > -1) {
            if (mSelectionPos > -1) {
                float caretx = cursorIndex2Position(mCursorPos, textBound[2],
                                                    glyphs, nglyphs);
                float selx = cursorIndex2Position(mSelectionPos, textBound[2],
                                                  glyphs, nglyphs);

                if (caretx > selx)
                    std::swap(caretx, selx);

                // draw selection
                nvgBeginPath(ctx);
                nvgFillColor(ctx, nvgRGBA(255, 255, 255, 80));
                nvgRect(ctx, caretx, drawPos.y() - lineh * 0.5f, selx - caretx,
                        lineh);
                nvgFill(ctx);
            }

            float caretx = cursorIndex2Position(mCursorPos, textBound[2], glyphs, nglyphs);

            // draw cursor
            nvgBeginPath(ctx);
            nvgMoveTo(ctx, caretx, drawPos.y() - lineh * 0.5f);
            nvgLineTo(ctx, caretx, drawPos.y() + lineh * 0.5f);
            nvgStrokeColor(ctx, nvgRGBA(255, 192, 0, 255));
            nvgStrokeWidth(ctx, 1.0f);
            nvgStroke(ctx);
        }
    }

    nvgResetScissor(ctx);
}