Пример #1
0
func drawCaps(ctx *nanovgo.Context, x, y, width float32) {
	caps := []nanovgo.LineCap{nanovgo.Butt, nanovgo.Round, nanovgo.Square}
	var lineWidth float32 = 8.0

	ctx.Save()
	defer ctx.Restore()

	ctx.BeginPath()
	ctx.Rect(x-lineWidth/2, y, width+lineWidth, 40)
	ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 32))
	ctx.Fill()

	ctx.BeginPath()
	ctx.Rect(x, y, width, 40)
	ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 32))
	ctx.Fill()

	ctx.SetStrokeWidth(lineWidth)

	for i, cap := range caps {
		ctx.SetLineCap(cap)
		ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 255))
		ctx.BeginPath()
		ctx.MoveTo(x, y+float32(i)*10+5)
		ctx.LineTo(x+width, y+float32(i)*10+5)
		ctx.Stroke()
	}
}
Пример #2
0
func (sf *SpinnerFilter) Draw(self nanogui.Widget, ctx *nanovgo.Context) {
	if sf.isActive() {
		var py int
		fw, fh := sf.Parent().Size()
		if window, ok := sf.Parent().(*nanogui.Window); ok {
			hh := window.Theme().WindowHeaderHeight
			py += hh
			fh -= hh
		}
		sf.SetPosition(0, py)
		sf.SetSize(fw, fh)

		currentTime := nanogui.GetTime() - sf.startTime

		var alpha float32
		var showSpinner bool
		if sf.state == SpinnerFadeIn {
			if currentTime > 1 {
				alpha = 0.7
				showSpinner = true
			} else {
				alpha = currentTime * 0.7
			}
		} else {
			if currentTime > 1 {
				alpha = 0.7
			} else {
				alpha = (1.0 - currentTime) * 0.7
			}
		}
		ctx.Save()
		ctx.BeginPath()
		ctx.SetFillColor(nanovgo.MONOf(0, alpha))
		ctx.Rect(0, float32(py), float32(fw), float32(fh))
		ctx.Fill()
		if showSpinner {
			cx := float32(fw / 2)
			cy := float32(py + fh/2)
			rotation := 2 * math.Pi * float64(currentTime*float32(sf.speed)*float32(sf.num)) / float64(sf.num)
			dr := float64(2 * math.Pi / float64(sf.num))
			ctx.SetStrokeWidth(sf.lineWidth)
			for i := 0; i < sf.num; i++ {
				ctx.BeginPath()
				ctx.MoveTo(cx+float32(math.Cos(rotation))*sf.c1, cy+float32(math.Sin(rotation))*sf.c1)
				ctx.LineTo(cx+float32(math.Cos(rotation))*sf.c2, cy+float32(math.Sin(rotation))*sf.c2)
				ctx.SetStrokeColor(nanovgo.MONOf(1.0, float32(i)/float32(sf.num)))
				ctx.Stroke()
				rotation += dr
			}
		}
		ctx.Restore()
	} else {
		sf.SetSize(0, 0)
		sf.SetVisible(false)
		return
	}
}
Пример #3
0
func (g *Graph) Draw(self Widget, ctx *nanovgo.Context) {
	g.WidgetImplement.Draw(self, ctx)

	x := float32(g.x)
	y := float32(g.y)
	w := float32(g.w)
	h := float32(g.h)

	ctx.BeginPath()
	ctx.Rect(x, y, w, h)
	ctx.SetFillColor(g.backgroundColor)
	ctx.Fill()

	if len(g.values) < 2 {
		return
	}

	ctx.BeginPath()
	ctx.MoveTo(x, y+h)
	dx := float32(len(g.values) - 1)
	for i, v := range g.values {
		vx := x + float32(i)*w/dx
		vy := y + (1.0-v)*h
		ctx.LineTo(vx, vy)
	}

	ctx.LineTo(x+w, y+h)
	ctx.SetStrokeColor(nanovgo.MONO(100, 255))
	ctx.Stroke()
	ctx.SetFillColor(g.foregroundColor)
	ctx.Fill()

	ctx.SetFontFace(g.theme.FontNormal)
	ctx.SetFillColor(g.textColor)
	if g.caption != "" {
		ctx.SetFontSize(14)
		ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignTop)
		ctx.Text(x+3, y+1, g.caption)
	}

	if g.header != "" {
		ctx.SetFontSize(18)
		ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignTop)
		ctx.Text(x+w-3, y+1, g.header)
	}

	if g.footer != "" {
		ctx.SetFontSize(15)
		ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignBottom)
		ctx.Text(x+w-3, y+h-1, g.footer)
	}

	ctx.BeginPath()
	ctx.Rect(x, y, w, h)
	ctx.SetStrokeColor(nanovgo.MONO(100, 255))
	ctx.Stroke()
}
Пример #4
0
func drawWindow(ctx *nanovgo.Context, title string, x, y, w, h float32) {
	var cornerRadius float32 = 3.0

	ctx.Save()
	defer ctx.Restore()
	//      ctx.Reset();

	// Window
	ctx.BeginPath()
	ctx.RoundedRect(x, y, w, h, cornerRadius)
	ctx.SetFillColor(nanovgo.RGBA(28, 30, 34, 192))
	//      ctx.FillColor(nanovgo.RGBA(0,0,0,128));
	ctx.Fill()

	// Drop shadow
	shadowPaint := nanovgo.BoxGradient(x, y+2, w, h, cornerRadius*2, 10, nanovgo.RGBA(0, 0, 0, 128), nanovgo.RGBA(0, 0, 0, 0))
	ctx.BeginPath()
	ctx.Rect(x-10, y-10, w+20, h+30)
	ctx.RoundedRect(x, y, w, h, cornerRadius)
	ctx.PathWinding(nanovgo.Hole)
	ctx.SetFillPaint(shadowPaint)
	ctx.Fill()

	// Header
	headerPaint := nanovgo.LinearGradient(x, y, x, y+15, nanovgo.RGBA(255, 255, 255, 8), nanovgo.RGBA(0, 0, 0, 16))
	ctx.BeginPath()
	ctx.RoundedRect(x+1, y+1, w-2, 30, cornerRadius-1)
	ctx.SetFillPaint(headerPaint)
	ctx.Fill()
	ctx.BeginPath()
	ctx.MoveTo(x+0.5, y+0.5+30)
	ctx.LineTo(x+0.5+w-1, y+0.5+30)
	ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 32))
	ctx.Stroke()

	ctx.SetFontSize(18.0)
	ctx.SetFontFace("sans-bold")
	ctx.SetTextAlign(nanovgo.AlignCenter | nanovgo.AlignMiddle)

	ctx.SetFontBlur(2)
	ctx.SetFillColor(nanovgo.RGBA(0, 0, 0, 128))
	ctx.Text(x+w/2, y+16+1, title)

	ctx.SetFontBlur(0)
	ctx.SetFillColor(nanovgo.RGBA(220, 220, 220, 160))
	ctx.Text(x+w/2, y+16, title)
}
Пример #5
0
func (i *ImagePanel) Draw(self Widget, ctx *nanovgo.Context) {
	cols, _ := i.gridSize()

	x := float32(i.x)
	y := float32(i.y)
	thumbSize := float32(i.thumbSize)

	for j, image := range i.images {
		pX := x + float32(i.margin+(j%cols)*(i.thumbSize+i.spacing))
		pY := y + float32(i.margin+(j/cols)*(i.thumbSize+i.spacing))

		imgW, imgH, _ := ctx.ImageSize(image.ImageID)
		var iw, ih, ix, iy float32
		if imgW < imgH {
			iw = thumbSize
			ih = iw * float32(imgH) / float32(imgW)
			ix = 0
			iy = -(ih - thumbSize) * 0.5
		} else {
			ih = thumbSize
			iw = ih * float32(imgH) / float32(imgW)
			iy = 0
			ix = -(iw - thumbSize) * 0.5
		}
		imgPaint := nanovgo.ImagePattern(pX+ix, pY+iy, iw, ih, 0, image.ImageID, toF(i.mouseIndex == j, 1.0, 0.7))
		ctx.BeginPath()
		ctx.RoundedRect(pX, pY, thumbSize, thumbSize, 5)
		ctx.SetFillPaint(imgPaint)
		ctx.Fill()

		shadowPaint := nanovgo.BoxGradient(pX-1, pY, thumbSize+2, thumbSize+2, 5, 3, nanovgo.MONO(0, 128), nanovgo.MONO(0, 0))

		ctx.BeginPath()
		ctx.Rect(pX-5, pY-5, thumbSize+10, thumbSize+10)
		ctx.RoundedRect(pX, pY, thumbSize, thumbSize, 6)
		ctx.PathWinding(nanovgo.Hole)
		ctx.SetFillPaint(shadowPaint)
		ctx.Fill()

		ctx.BeginPath()
		ctx.RoundedRect(pX+0.5, pY+0.5, thumbSize-1, thumbSize-1, 4-0.5)
		ctx.SetStrokeWidth(1.0)
		ctx.SetStrokeColor(nanovgo.MONO(255, 80))
		ctx.Stroke()
	}
}
Пример #6
0
// RenderGraph shows graph
func (pg *PerfGraph) RenderGraph(ctx *nanovgo.Context, x, y float32) {
	avg := pg.GetGraphAverage()
	var w float32 = 200
	var h float32 = 35

	ctx.BeginPath()
	ctx.Rect(x, y, w, h)
	ctx.SetFillColor(backgroundColor)
	ctx.Fill()

	ctx.BeginPath()
	ctx.MoveTo(x, y+h)
	for i := 0; i < nvgGraphHistoryCount; i++ {
		v := float32(1.0) / float32(0.00001+pg.values[(pg.head+i)%nvgGraphHistoryCount])
		if v > 80.0 {
			v = 80.0
		}
		vx := x + float32(i)/float32(nvgGraphHistoryCount-1)*w
		vy := y + h - ((v / 80.0) * h)
		ctx.LineTo(vx, vy)
	}
	ctx.LineTo(x+w, y+h)
	ctx.SetFillColor(graphColor)
	ctx.Fill()

	ctx.SetFontFace(pg.fontFace)

	if len(pg.name) > 0 {
		ctx.SetFontSize(14.0)
		ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignTop)
		ctx.SetFillColor(titleTextColor)
		ctx.Text(x+3, y+1, pg.name)
	}

	ctx.SetFontSize(18.0)
	ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignTop)
	ctx.SetFillColor(fpsTextColor)
	ctx.Text(x+w-3, y+1, fmt.Sprintf("%.2f FPS", 1.0/avg))

	ctx.SetFontSize(15.0)
	ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignBottom)
	ctx.SetFillColor(averageTextColor)
	ctx.Text(x+w-3, y+h+1, fmt.Sprintf("%.2f ms", avg*1000.0))
}
Пример #7
0
func (i *ImageView) Draw(self Widget, ctx *nanovgo.Context) {
	if i.image == 0 {
		return
	}
	x := float32(i.x)
	y := float32(i.y)
	ow := float32(i.w)
	oh := float32(i.h)

	var w, h float32
	{
		iw, ih, _ := ctx.ImageSize(i.image)
		w = float32(iw)
		h = float32(ih)
	}

	if i.policy == ImageSizePolicyFixed {
		if ow < w {
			h = float32(int(h * ow / w))
			w = ow
		}
		if oh < h {
			w = float32(int(w * oh / h))
			h = oh
		}
	} else { // mPolicy == Expand
		// expand to width
		h = float32(int(h * ow / w))
		w = ow
		// shrink to height, if necessary
		if oh < h {
			w = float32(int(w * oh / h))
			h = oh
		}
	}

	imgPaint := nanovgo.ImagePattern(x, y, w, h, 0, i.image, 1.0)

	ctx.BeginPath()
	ctx.Rect(x, y, w, h)
	ctx.SetFillPaint(imgPaint)
	ctx.Fill()
}
Пример #8
0
// Draw() draws the widget (and all child widgets)
func (w *WidgetImplement) Draw(self Widget, ctx *nanovgo.Context) {
	if debugFlag {
		ctx.SetStrokeWidth(1.0)
		ctx.BeginPath()
		ctx.Rect(float32(w.x)-0.5, float32(w.y)-0.5, float32(w.w)+1.0, float32(w.h)+1.0)
		ctx.SetStrokeColor(nanovgo.RGBA(255, 0, 0, 255))
		ctx.Stroke()
	}

	if len(w.children) == 0 {
		return
	}
	ctx.Translate(float32(w.x), float32(w.y))
	// draw depth 0 items
	var drawLater widgetsAsc = make([]Widget, 0, len(w.children))
	for _, child := range w.children {
		if child.Visible() {
			depth := child.Depth()
			if depth == 0 {
				cx, cy := child.Position()
				cw, ch := child.Size()
				if !self.IsClipped(cx, cy, cw, ch) {
					child.Draw(child, ctx)
				}
			} else {
				drawLater = append(drawLater, child)
			}
		}
	}
	// draw by depth order
	sort.Sort(drawLater)
	for _, child := range drawLater {
		cx, cy := child.Position()
		cw, ch := child.Size()
		if !self.IsClipped(cx, cy, cw, ch) {
			child.Draw(child, ctx)
		}
	}
	ctx.Translate(-float32(w.x), -float32(w.y))
}
Пример #9
0
func drawScissor(ctx *nanovgo.Context, x, y, t float32) {
	ctx.Save()

	// Draw first rect and set scissor to it's area.
	ctx.Translate(x, y)
	ctx.Rotate(nanovgo.DegToRad(5))
	ctx.BeginPath()
	ctx.Rect(-20, -20, 60, 40)
	ctx.SetFillColor(nanovgo.RGBA(255, 0, 0, 255))
	ctx.Fill()
	ctx.Scissor(-20, -20, 60, 40)

	// Draw second rectangle with offset and rotation.
	ctx.Translate(40, 0)
	ctx.Rotate(t)

	// Draw the intended second rectangle without any scissoring.
	ctx.Save()
	ctx.ResetScissor()
	ctx.BeginPath()
	ctx.Rect(-20, -10, 60, 30)
	ctx.SetFillColor(nanovgo.RGBA(255, 128, 0, 64))
	ctx.Fill()
	ctx.Restore()

	// Draw second rectangle with combined scissoring.
	ctx.IntersectScissor(-20, -10, 60, 30)
	ctx.BeginPath()
	ctx.Rect(-20, -10, 60, 30)
	ctx.SetFillColor(nanovgo.RGBA(255, 128, 0, 255))
	ctx.Fill()

	ctx.Restore()
}
Пример #10
0
func (p *Popup) Draw(self Widget, ctx *nanovgo.Context) {
	p.RefreshRelativePlacement()

	if !p.visible {
		return
	}
	ds := float32(p.theme.WindowDropShadowSize)
	cr := float32(p.theme.WindowCornerRadius)

	px := float32(p.x)
	py := float32(p.y)
	pw := float32(p.w)
	ph := float32(p.h)
	ah := float32(p.anchorHeight)

	/* Draw a drop shadow */
	shadowPaint := nanovgo.BoxGradient(px, py, pw, ph, cr*2, ds*2, p.theme.DropShadow, p.theme.Transparent)
	ctx.BeginPath()
	ctx.Rect(px-ds, py-ds, pw+ds*2, ph+ds*2)
	ctx.RoundedRect(px, py, pw, ph, cr)
	ctx.PathWinding(nanovgo.Hole)
	ctx.SetFillPaint(shadowPaint)
	ctx.Fill()

	/* Draw window */
	ctx.BeginPath()
	ctx.RoundedRect(px, py, pw, ph, cr)

	ctx.MoveTo(px-15, py+ah)
	ctx.LineTo(px+1, py+ah-15)
	ctx.LineTo(px+1, py+ah+15)

	ctx.SetFillColor(p.theme.WindowPopup)

	ctx.Fill()

	p.WidgetImplement.Draw(self, ctx)
}
Пример #11
0
func drawSlider(ctx *nanovgo.Context, pos, x, y, w, h float32) {
	cy := y + float32(int(h*0.5))
	kr := float32(int(h * 0.25))

	ctx.Save()
	defer ctx.Restore()
	//      ctx.ClearState(vg);

	// Slot
	bg := nanovgo.BoxGradient(x, cy-2+1, w, 4, 2, 2, nanovgo.RGBA(0, 0, 0, 32), nanovgo.RGBA(0, 0, 0, 128))
	ctx.BeginPath()
	ctx.RoundedRect(x, cy-2, w, 4, 2)
	ctx.SetFillPaint(bg)
	ctx.Fill()

	// Knob Shadow
	bg = nanovgo.RadialGradient(x+float32(int(pos*w)), cy+1, kr-3, kr+3, nanovgo.RGBA(0, 0, 0, 64), nanovgo.RGBA(0, 0, 0, 0))
	ctx.BeginPath()
	ctx.Rect(x+float32(int(pos*w))-kr-5, cy-kr-5, kr*2+5+5, kr*2+5+5+3)
	ctx.Circle(x+float32(int(pos*w)), cy, kr)
	ctx.PathWinding(nanovgo.Hole)
	ctx.SetFillPaint(bg)
	ctx.Fill()

	// Knob
	knob := nanovgo.LinearGradient(x, cy-kr, x, cy+kr, nanovgo.RGBA(255, 255, 255, 16), nanovgo.RGBA(0, 0, 0, 16))
	ctx.BeginPath()
	ctx.Circle(x+float32(int(pos*w)), cy, kr-1)
	ctx.SetFillColor(nanovgo.RGBA(40, 43, 48, 255))
	ctx.Fill()
	ctx.SetFillPaint(knob)
	ctx.Fill()

	ctx.BeginPath()
	ctx.Circle(x+float32(int(pos*w)), cy, kr-0.5)
	ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 92))
	ctx.Stroke()
}
Пример #12
0
func drawParagraph(ctx *nanovgo.Context, x, y, width, height, mx, my float32) {
	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."

	ctx.Save()
	defer ctx.Restore()

	ctx.SetFontSize(18.0)
	ctx.SetFontFace("sans")
	ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignTop)
	_, _, lineh := ctx.TextMetrics()
	// 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.
	runes := []rune(text)

	var gx, gy float32
	var gutter int
	lnum := 0

	for _, row := range ctx.TextBreakLinesRune(runes, width) {
		hit := mx > x && mx < (x+width) && my >= y && my < (y+lineh)

		ctx.BeginPath()
		var alpha uint8
		if hit {
			alpha = 64
		} else {
			alpha = 16
		}
		ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, alpha))
		ctx.Rect(x, y, row.Width, lineh)
		ctx.Fill()

		ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 255))
		ctx.TextRune(x, y, runes[row.StartIndex:row.EndIndex])

		if hit {
			var caretX float32
			if mx < x+row.Width/2 {
				caretX = x
			} else {
				caretX = x + row.Width
			}
			px := x
			lineRune := runes[row.StartIndex:row.EndIndex]
			glyphs := ctx.TextGlyphPositionsRune(x, y, lineRune)
			for j, glyph := range glyphs {
				x0 := glyph.X
				var x1 float32
				if j+1 < len(glyphs) {
					x1 = glyphs[j+1].X
				} else {
					x1 = x + row.Width
				}
				gx = x0*0.3 + x1*0.7
				if mx >= px && mx < gx {
					caretX = glyph.X
				}
				px = gx
			}
			ctx.BeginPath()
			ctx.SetFillColor(nanovgo.RGBA(255, 192, 0, 255))
			ctx.Rect(caretX, y, 1, lineh)
			ctx.Fill()

			gutter = lnum + 1
			gx = x - 10
			gy = y + lineh/2
		}
		lnum++
		y += lineh
	}

	if gutter > 0 {
		txt := strconv.Itoa(gutter)

		ctx.SetFontSize(13.0)
		ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignMiddle)

		_, bounds := ctx.TextBounds(gx, gy, txt)

		ctx.BeginPath()
		ctx.SetFillColor(nanovgo.RGBA(255, 192, 0, 255))
		ctx.RoundedRect(
			float32(int(bounds[0]-4)),
			float32(int(bounds[1]-2)),
			float32(int(bounds[2]-bounds[0])+8),
			float32(int(bounds[3]-bounds[1])+4),
			float32(int(bounds[3]-bounds[1])+4)/2.0-1.0)
		ctx.Fill()

		ctx.SetFillColor(nanovgo.RGBA(32, 32, 32, 255))
		ctx.Text(gx, gy, txt)
	}

	y += 20.0

	ctx.SetFontSize(13.0)
	ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignTop)
	ctx.SetTextLineHeight(1.2)

	bounds := ctx.TextBoxBounds(x, y, 150, "Hover your mouse over the text to see calculated caret position.")

	// Fade the tooltip out when close to it.
	gx = absF((mx - (bounds[0]+bounds[2])*0.5) / (bounds[0] - bounds[2]))
	gy = absF((my - (bounds[1]+bounds[3])*0.5) / (bounds[1] - bounds[3]))
	a := maxF(gx, gy) - 0.5
	a = clampF(a, 0, 1)
	ctx.SetGlobalAlpha(a)

	ctx.BeginPath()
	ctx.SetFillColor(nanovgo.RGBA(220, 220, 220, 255))
	ctx.RoundedRect(bounds[0]-2, bounds[1]-2, float32(int(bounds[2]-bounds[0])+4), float32(int(bounds[3]-bounds[1])+4), 3)
	px := float32(int((bounds[2] + bounds[0]) / 2))
	ctx.MoveTo(px, bounds[1]-10)
	ctx.LineTo(px+7, bounds[1]+1)
	ctx.LineTo(px-7, bounds[1]+1)
	ctx.Fill()

	ctx.SetFillColor(nanovgo.RGBA(0, 0, 0, 220))
	ctx.TextBox(x, y, 150, "Hover your mouse over the text to see calculated caret position.")
}
Пример #13
0
func drawColorWheel(ctx *nanovgo.Context, x, y, w, h, t float32) {
	var r0, r1, ax, ay, bx, by, aeps, r float32
	hue := sinF(t * 0.12)

	ctx.Save()
	defer ctx.Restore()
	/*      ctx.BeginPath()
	ctx.Rect(x,y,w,h)
	ctx.FillColor(nanovgo.RGBA(255,0,0,128))
	ctx.Fill()*/

	cx := x + w*0.5
	cy := y + h*0.5
	if w < h {
		r1 = w*0.5 - 5.0
	} else {
		r1 = h*0.5 - 5.0
	}
	r0 = r1 - 20.0
	aeps = 0.5 / r1 // half a pixel arc length in radians (2pi cancels out).

	for i := 0; i < 6; i++ {
		a0 := float32(i)/6.0*nanovgo.PI*2.0 - aeps
		a1 := float32(i+1.0)/6.0*nanovgo.PI*2.0 + aeps
		ctx.BeginPath()
		ctx.Arc(cx, cy, r0, a0, a1, nanovgo.Clockwise)
		ctx.Arc(cx, cy, r1, a1, a0, nanovgo.CounterClockwise)
		ctx.ClosePath()
		ax = cx + cosF(a0)*(r0+r1)*0.5
		ay = cy + sinF(a0)*(r0+r1)*0.5
		bx = cx + cosF(a1)*(r0+r1)*0.5
		by = cy + sinF(a1)*(r0+r1)*0.5
		paint := nanovgo.LinearGradient(ax, ay, bx, by, nanovgo.HSLA(a0/(nanovgo.PI*2), 1.0, 0.55, 255), nanovgo.HSLA(a1/(nanovgo.PI*2), 1.0, 0.55, 255))
		ctx.SetFillPaint(paint)
		ctx.Fill()
	}

	ctx.BeginPath()
	ctx.Circle(cx, cy, r0-0.5)
	ctx.Circle(cx, cy, r1+0.5)
	ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 64))
	ctx.SetStrokeWidth(1.0)
	ctx.Stroke()

	// Selector
	ctx.Translate(cx, cy)
	ctx.Rotate(hue * nanovgo.PI * 2)

	// Marker on
	ctx.SetStrokeWidth(2.0)
	ctx.BeginPath()
	ctx.Rect(r0-1, -3, r1-r0+2, 6)
	ctx.SetStrokeColor(nanovgo.RGBA(255, 255, 255, 192))
	ctx.Stroke()

	paint := nanovgo.BoxGradient(r0-3, -5, r1-r0+6, 10, 2, 4, nanovgo.RGBA(0, 0, 0, 128), nanovgo.RGBA(0, 0, 0, 0))
	ctx.BeginPath()
	ctx.Rect(r0-2-10, -4-10, r1-r0+4+20, 8+20)
	ctx.Rect(r0-2, -4, r1-r0+4, 8)
	ctx.PathWinding(nanovgo.Hole)
	ctx.SetFillPaint(paint)
	ctx.Fill()

	// Center triangle
	r = r0 - 6
	ax = cosF(120.0/180.0*nanovgo.PI) * r
	ay = sinF(120.0/180.0*nanovgo.PI) * r
	bx = cosF(-120.0/180.0*nanovgo.PI) * r
	by = sinF(-120.0/180.0*nanovgo.PI) * r
	ctx.BeginPath()
	ctx.MoveTo(r, 0)
	ctx.LineTo(ax, ay)
	ctx.LineTo(bx, by)
	ctx.ClosePath()
	paint = nanovgo.LinearGradient(r, 0, ax, ay, nanovgo.HSLA(hue, 1.0, 0.5, 255), nanovgo.RGBA(255, 255, 255, 255))
	ctx.SetFillPaint(paint)
	ctx.Fill()
	paint = nanovgo.LinearGradient((r+ax)*0.5, (0+ay)*0.5, bx, by, nanovgo.RGBA(0, 0, 0, 0), nanovgo.RGBA(0, 0, 0, 255))
	ctx.SetFillPaint(paint)
	ctx.Fill()
	ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 64))
	ctx.Stroke()

	// Select circle on triangle
	ax = cosF(120.0/180.0*nanovgo.PI) * r * 0.3
	ay = sinF(120.0/180.0*nanovgo.PI) * r * 0.4
	ctx.SetStrokeWidth(2.0)
	ctx.BeginPath()
	ctx.Circle(ax, ay, 5)
	ctx.SetStrokeColor(nanovgo.RGBA(255, 255, 255, 192))
	ctx.Stroke()

	paint = nanovgo.RadialGradient(ax, ay, 7, 9, nanovgo.RGBA(0, 0, 0, 64), nanovgo.RGBA(0, 0, 0, 0))
	ctx.BeginPath()
	ctx.Rect(ax-20, ay-20, 40, 40)
	ctx.Circle(ax, ay, 7)
	ctx.PathWinding(nanovgo.Hole)
	ctx.SetFillPaint(paint)
	ctx.Fill()
}
Пример #14
0
func drawThumbnails(ctx *nanovgo.Context, x, y, w, h float32, images []int, t float32) {
	var cornerRadius float32 = 3.0

	var thumb float32 = 60.0
	var arry float32 = 30.5
	stackh := float32(len(images)/2)*(thumb+10) + 10
	u := (1 + cosF(t*0.5)) * 0.5
	u2 := (1 - cosF(t*0.2)) * 0.5

	ctx.Save()
	defer ctx.Restore()

	// Drop shadow
	shadowPaint := nanovgo.BoxGradient(x, y+4, w, h, cornerRadius*2, 20, nanovgo.RGBA(0, 0, 0, 128), nanovgo.RGBA(0, 0, 0, 0))
	ctx.BeginPath()
	ctx.Rect(x-10, y-10, w+20, h+30)
	ctx.RoundedRect(x, y, w, h, cornerRadius)
	ctx.PathWinding(nanovgo.Hole)
	ctx.SetFillPaint(shadowPaint)
	ctx.Fill()

	// Window
	ctx.BeginPath()
	ctx.RoundedRect(x, y, w, h, cornerRadius)
	ctx.MoveTo(x-10, y+arry)
	ctx.LineTo(x+1, y+arry-11)
	ctx.LineTo(x+1, y+arry+11)
	ctx.SetFillColor(nanovgo.RGBA(200, 200, 200, 255))
	ctx.Fill()

	ctx.Block(func() {
		ctx.Scissor(x, y, w, h)
		ctx.Translate(0, -(stackh-h)*u)

		dv := 1.0 / float32(len(images)-1)

		for i, imageID := range images {
			tx := x + 10.0
			ty := y + 10.0
			tx += float32(i%2) * (thumb + 10.0)
			ty += float32(i/2) * (thumb + 10.0)
			imgW, imgH, _ := ctx.ImageSize(imageID)
			var iw, ih, ix, iy float32
			if imgW < imgH {
				iw = thumb
				ih = iw * float32(imgH) / float32(imgW)
				ix = 0
				iy = -(ih - thumb) * 0.5
			} else {
				ih = thumb
				iw = ih * float32(imgW) / float32(imgH)
				ix = -(iw - thumb) * 0.5
				iy = 0
			}

			v := float32(i) * dv
			a := clampF((u2-v)/dv, 0, 1)

			if a < 1.0 {
				drawSpinner(ctx, tx+thumb/2, ty+thumb/2, thumb*0.25, t)
			}

			imgPaint := nanovgo.ImagePattern(tx+ix, ty+iy, iw, ih, 0.0/180.0*nanovgo.PI, imageID, a)
			ctx.BeginPath()
			ctx.RoundedRect(tx, ty, thumb, thumb, 5)
			ctx.SetFillPaint(imgPaint)
			ctx.Fill()

			shadowPaint := nanovgo.BoxGradient(tx-1, ty, thumb+2, thumb+2, 5, 3, nanovgo.RGBA(0, 0, 0, 128), nanovgo.RGBA(0, 0, 0, 0))
			ctx.BeginPath()
			ctx.Rect(tx-5, ty-5, thumb+10, thumb+10)
			ctx.RoundedRect(tx, ty, thumb, thumb, 6)
			ctx.PathWinding(nanovgo.Hole)
			ctx.SetFillPaint(shadowPaint)
			ctx.Fill()

			ctx.BeginPath()
			ctx.RoundedRect(tx+0.5, ty+0.5, thumb-1, thumb-1, 4-0.5)
			ctx.SetStrokeWidth(1.0)
			ctx.SetStrokeColor(nanovgo.RGBA(255, 255, 255, 192))
			ctx.Stroke()
		}
	})

	// Hide fades
	fadePaint := nanovgo.LinearGradient(x, y, x, y+6, nanovgo.RGBA(200, 200, 200, 255), nanovgo.RGBA(200, 200, 200, 0))
	ctx.BeginPath()
	ctx.Rect(x+4, y, w-8, 6)
	ctx.SetFillPaint(fadePaint)
	ctx.Fill()

	fadePaint = nanovgo.LinearGradient(x, y+h, x, y+h-6, nanovgo.RGBA(200, 200, 200, 255), nanovgo.RGBA(200, 200, 200, 0))
	ctx.BeginPath()
	ctx.Rect(x+4, y+h-6, w-8, 6)
	ctx.SetFillPaint(fadePaint)
	ctx.Fill()

	// Scroll bar
	shadowPaint = nanovgo.BoxGradient(x+w-12+1, y+4+1, 8, h-8, 3, 4, nanovgo.RGBA(0, 0, 0, 32), nanovgo.RGBA(0, 0, 0, 92))
	ctx.BeginPath()
	ctx.RoundedRect(x+w-12, y+4, 8, h-8, 3)
	ctx.SetFillPaint(shadowPaint)
	//      ctx.FillColor(ctx.RGBA(255,0,0,128));
	ctx.Fill()

	scrollH := (h / stackh) * (h - 8)
	shadowPaint = nanovgo.BoxGradient(x+w-12-1, y+4+(h-8-scrollH)*u-1, 8, scrollH, 3, 4, nanovgo.RGBA(220, 220, 220, 255), nanovgo.RGBA(128, 128, 128, 255))
	ctx.BeginPath()
	ctx.RoundedRect(x+w-12+1, y+4+1+(h-8-scrollH)*u, 8-2, scrollH-2, 2)
	ctx.SetFillPaint(shadowPaint)
	//      ctx.FillColor(ctx.RGBA(0,0,0,128));
	ctx.Fill()
}
Пример #15
0
func drawGraph(ctx *nanovgo.Context, x, y, w, h, t float32) {
	var sx, sy [6]float32
	dx := w / 5.0

	samples := []float32{
		(1 + sinF(t*1.2345+cosF(t*0.33457)*0.44)) * 0.5,
		(1 + sinF(t*0.68363+cosF(t*1.3)*1.55)) * 0.5,
		(1 + sinF(t*1.1642+cosF(t*0.33457)*1.24)) * 0.5,
		(1 + sinF(t*0.56345+cosF(t*1.63)*0.14)) * 0.5,
		(1 + sinF(t*1.6245+cosF(t*0.254)*0.3)) * 0.5,
		(1 + sinF(t*0.345+cosF(t*0.03)*0.6)) * 0.5,
	}

	for i := 0; i < 6; i++ {
		sx[i] = x + float32(i)*dx
		sy[i] = y + h*samples[i]*0.8
	}

	// Graph background
	bg := nanovgo.LinearGradient(x, y, x, y+h, nanovgo.RGBA(0, 160, 192, 0), nanovgo.RGBA(0, 160, 192, 64))
	ctx.BeginPath()
	ctx.MoveTo(sx[0], sy[0])
	for i := 1; i < 6; i++ {
		ctx.BezierTo(sx[i-1]+dx*0.5, sy[i-1], sx[i]-dx*0.5, sy[i], sx[i], sy[i])
	}
	ctx.LineTo(x+w, y+h)
	ctx.LineTo(x, y+h)
	ctx.SetFillPaint(bg)
	ctx.Fill()

	// Graph line
	ctx.BeginPath()
	ctx.MoveTo(sx[0], sy[0]+2)
	for i := 1; i < 6; i++ {
		ctx.BezierTo(sx[i-1]+dx*0.5, sy[i-1]+2, sx[i]-dx*0.5, sy[i]+2, sx[i], sy[i]+2)
	}
	ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 32))
	ctx.SetStrokeWidth(3.0)
	ctx.Stroke()

	ctx.BeginPath()
	ctx.MoveTo(sx[0], sy[0])
	for i := 1; i < 6; i++ {
		ctx.BezierTo(sx[i-1]+dx*0.5, sy[i-1], sx[i]-dx*0.5, sy[i], sx[i], sy[i])
	}
	ctx.SetStrokeColor(nanovgo.RGBA(0, 160, 192, 255))
	ctx.SetStrokeWidth(3.0)
	ctx.Stroke()

	// Graph sample pos
	for i := 0; i < 6; i++ {
		bg = nanovgo.RadialGradient(sx[i], sy[i]+2, 3.0, 8.0, nanovgo.RGBA(0, 0, 0, 32), nanovgo.RGBA(0, 0, 0, 0))
		ctx.BeginPath()
		ctx.Rect(sx[i]-10, sy[i]-10+2, 20, 20)
		ctx.SetFillPaint(bg)
		ctx.Fill()
	}

	ctx.BeginPath()
	for i := 0; i < 6; i++ {
		ctx.Circle(sx[i], sy[i], 4.0)
	}
	ctx.SetFillColor(nanovgo.RGBA(0, 160, 192, 255))
	ctx.Fill()
	ctx.BeginPath()
	for i := 0; i < 6; i++ {
		ctx.Circle(sx[i], sy[i], 2.0)
	}
	ctx.SetFillColor(nanovgo.RGBA(220, 220, 220, 255))
	ctx.Fill()

	ctx.SetStrokeWidth(1.0)
}
Пример #16
0
func (c *ColorWheel) Draw(self Widget, ctx *nanovgo.Context) {
	c.WidgetImplement.Draw(self, ctx)

	if !c.visible {
		return
	}
	x := float32(c.x)
	y := float32(c.y)
	w := float32(c.w)
	h := float32(c.h)

	ctx.Save()
	defer ctx.Restore()

	cx := x + w*0.5
	cy := y + h*0.5
	r1 := toF(w < h, w, h)*0.5 - 5.0
	r0 := r1 * 0.75

	aeps := 0.7 / r1 // half a pixel arc length in radians (2pi cancels out).
	for i := 0; i < 6; i++ {
		a0 := float32(i)/6.0*nanovgo.PI*2.0 - aeps
		a1 := float32(i+1)/6.0*nanovgo.PI*2.0 + aeps
		ctx.BeginPath()
		ctx.Arc(cx, cy, r0, a0, a1, nanovgo.Clockwise)
		ctx.Arc(cx, cy, r1, a1, a0, nanovgo.CounterClockwise)
		ctx.ClosePath()

		sin1, cos1 := sinCosF(a0)
		sin2, cos2 := sinCosF(a1)
		ax := cx + cos1*(r0+r1)*0.5
		ay := cy + sin1*(r0+r1)*0.5
		bx := cx + cos2*(r0+r1)*0.5
		by := cy + sin2*(r0+r1)*0.5
		color1 := nanovgo.HSLA(a0/(nanovgo.PI*2), 1.0, 0.55, 255)
		color2 := nanovgo.HSLA(a1/(nanovgo.PI*2), 1.0, 0.55, 255)
		paint := nanovgo.LinearGradient(ax, ay, bx, by, color1, color2)
		ctx.SetFillPaint(paint)
		ctx.Fill()
	}

	ctx.BeginPath()
	ctx.Circle(cx, cy, r0-0.5)
	ctx.Circle(cx, cy, r1+0.5)
	ctx.SetStrokeColor(nanovgo.MONO(0, 64))
	ctx.Stroke()

	// Selector
	ctx.Save()
	defer ctx.Restore()
	ctx.Translate(cx, cy)
	ctx.Rotate(c.hue * nanovgo.PI * 2)

	// Marker on
	u := clampF(r1/50, 1.5, 4.0)
	ctx.SetStrokeWidth(u)
	ctx.BeginPath()
	ctx.Rect(r0-1, -2*u, r1-r0+2, 4*u)
	ctx.SetStrokeColor(nanovgo.MONO(255, 192))
	ctx.Stroke()

	paint := nanovgo.BoxGradient(r0-3, -5, r1-r0+6, 10, 2, 4, nanovgo.MONO(0, 128), nanovgo.MONO(0, 0))
	ctx.BeginPath()
	ctx.Rect(r0-2-10, -4-10, r1-r0+4+20, 8+20)
	ctx.Rect(r0-2, -4, r1-r0+4, 8)
	ctx.PathWinding(nanovgo.Hole)
	ctx.SetFillPaint(paint)
	ctx.Fill()

	// Center triangle
	r := r0 - 6
	sin1, cos1 := sinCosF(120.0 / 180.0 * nanovgo.PI)
	sin2, cos2 := sinCosF(-120.0 / 180.0 * nanovgo.PI)
	ax := cos1 * r
	ay := sin1 * r
	bx := cos2 * r
	by := sin2 * r
	ctx.BeginPath()
	ctx.MoveTo(r, 0)
	ctx.LineTo(ax, ay)
	ctx.LineTo(bx, by)
	ctx.ClosePath()
	triPaint1 := nanovgo.LinearGradient(r, 0, ax, ay, nanovgo.HSL(c.hue, 1.0, 0.5), nanovgo.MONO(255, 255))
	ctx.SetFillPaint(triPaint1)
	ctx.Fill()
	triPaint2 := nanovgo.LinearGradient((r+ax)*0.5, ay*0.5, bx, by, nanovgo.MONO(0, 0), nanovgo.MONO(0, 255))
	ctx.SetFillPaint(triPaint2)
	ctx.Fill()

	// selector circle on triangle
	px, py := c.calculatePosition()
	ctx.SetStrokeWidth(u)
	ctx.BeginPath()
	ctx.Circle(px, py, 2*u)
	ctx.SetStrokeColor(nanovgo.MONO(255, 192))
	ctx.Stroke()
}
Пример #17
0
func (w *Window) Draw(self Widget, ctx *nanovgo.Context) {
	ds := float32(w.theme.WindowDropShadowSize)
	cr := float32(w.theme.WindowCornerRadius)
	hh := float32(w.theme.WindowHeaderHeight)

	// Draw window
	wx := float32(w.x)
	wy := float32(w.y)
	ww := float32(w.w)
	wh := float32(w.h)
	ctx.Save()
	ctx.BeginPath()
	ctx.RoundedRect(wx, wy, ww, wh, cr)
	if w.mouseFocus {
		ctx.SetFillColor(w.theme.WindowFillFocused)
	} else {
		ctx.SetFillColor(w.theme.WindowFillUnfocused)
	}
	ctx.Fill()

	// Draw a drop shadow
	shadowPaint := nanovgo.BoxGradient(wx, wy, ww, wh, cr*2, ds*2, w.theme.DropShadow, w.theme.Transparent)
	ctx.BeginPath()
	ctx.Rect(wx-ds, wy-ds, ww+ds*2, wh+ds*2)
	ctx.RoundedRect(wx, wy, ww, wh, cr)
	ctx.PathWinding(nanovgo.Hole)
	ctx.SetFillPaint(shadowPaint)
	ctx.Fill()

	if w.title != "" {
		headerPaint := nanovgo.LinearGradient(wx, wy, ww, wh+hh, w.theme.WindowHeaderGradientTop, w.theme.WindowHeaderGradientBot)

		ctx.BeginPath()
		ctx.RoundedRect(wx, wy, ww, hh, cr)
		ctx.SetFillPaint(headerPaint)
		ctx.Fill()

		ctx.BeginPath()
		ctx.RoundedRect(wx, wy, ww, wh, cr)
		ctx.SetStrokeColor(w.theme.WindowHeaderSepTop)
		ctx.Scissor(wx, wy, ww, 0.5)
		ctx.Stroke()
		ctx.ResetScissor()

		ctx.BeginPath()
		ctx.MoveTo(wx+0.5, wy+hh-1.5)
		ctx.LineTo(wx+ww-0.5, wy+hh-1.5)
		ctx.SetStrokeColor(w.theme.WindowHeaderSepTop)
		ctx.Stroke()

		ctx.SetFontSize(18.0)
		ctx.SetFontFace(w.theme.FontBold)
		ctx.SetTextAlign(nanovgo.AlignCenter | nanovgo.AlignMiddle)
		ctx.SetFontBlur(2.0)
		ctx.SetFillColor(w.theme.DropShadow)
		ctx.Text(wx+ww*0.5, wy+hh*0.5, w.title)
		ctx.SetFontBlur(0.0)
		if w.focused {
			ctx.SetFillColor(w.theme.WindowTitleFocused)
		} else {
			ctx.SetFillColor(w.theme.WindowTitleUnfocused)
		}
		ctx.Text(wx+ww*0.5, wy+hh*0.5-1, w.title)
	}
	ctx.Restore()
	w.WidgetImplement.Draw(self, ctx)
}
Пример #18
0
func (t *TextBox) Draw(self Widget, ctx *nanovgo.Context) {
	t.WidgetImplement.Draw(self, ctx)

	x := float32(t.x)
	y := float32(t.y)
	w := float32(t.w)
	h := float32(t.h)

	bg := nanovgo.BoxGradient(x+1, y+2, w-2, h-2, 3, 4, nanovgo.MONO(255, 32), nanovgo.MONO(32, 32))
	fg1 := nanovgo.BoxGradient(x+1, y+2, w-2, h-2, 3, 4, nanovgo.MONO(150, 32), nanovgo.MONO(32, 32))
	fg2 := nanovgo.BoxGradient(x+1, y+2, w-2, h-2, 3, 4, nanovgo.RGBA(255, 0, 0, 100), nanovgo.RGBA(255, 0, 0, 50))

	ctx.BeginPath()
	ctx.RoundedRect(x+1, y+2, w-2, h-2, 3)
	if t.editable && t.Focused() {
		if t.validFormat {
			ctx.SetFillPaint(fg1)
		} else {
			ctx.SetFillPaint(fg2)
		}
	} else {
		ctx.SetFillPaint(bg)
	}

	ctx.Fill()

	ctx.BeginPath()
	ctx.RoundedRect(x+0.5, y+0.5, w-1, h-1, 2.5)
	ctx.SetStrokeColor(nanovgo.MONO(0, 48))
	ctx.Stroke()

	ctx.SetFontSize(float32(t.FontSize()))
	ctx.SetFontFace(t.Font())
	drawPosX := x
	drawPosY := y + h*0.5 + 1

	xSpacing := h * 0.3
	var unitWidth float32

	if t.unitImage > 0 {
		iw, ih, _ := ctx.ImageSize(t.unitImage)
		unitHeight := float32(ih) * 0.4
		unitWidth = float32(iw) * unitHeight / float32(h)
		imgPaint := nanovgo.ImagePattern(x+w-xSpacing-unitWidth, drawPosY-unitHeight*0.5,
			unitWidth, unitHeight, 0, t.unitImage, toF(t.enabled, 0.7, 0.35))
		ctx.BeginPath()
		ctx.Rect(x+w-xSpacing-unitWidth, drawPosY-unitHeight*0.5, unitWidth, unitHeight)
		ctx.SetFillPaint(imgPaint)
		ctx.Fill()
		unitWidth += 2
	} else if t.units != "" {
		unitWidth, _ = ctx.TextBounds(0, 0, t.units)
		ctx.SetFillColor(nanovgo.MONO(255, toB(t.enabled, 64, 32)))
		ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignMiddle)
		ctx.Text(x+w-xSpacing, drawPosY, t.units)
	}

	switch t.alignment {
	case TextLeft:
		ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignMiddle)
		drawPosX += xSpacing
	case TextRight:
		ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignMiddle)
		drawPosX += w - unitWidth - xSpacing
	case TextCenter:
		ctx.SetTextAlign(nanovgo.AlignCenter | nanovgo.AlignMiddle)
		drawPosX += w * 0.5
	}
	if t.enabled {
		ctx.SetFillColor(t.theme.TextColor)
	} else {
		ctx.SetFillColor(t.theme.DisabledTextColor)
	}
	// clip visible text area
	clipX := x + xSpacing - 1
	clipY := y + 1.0
	clipWidth := w - unitWidth - 2.0*xSpacing + 2.0
	clipHeight := h - 3.0
	ctx.Scissor(clipX, clipY, clipWidth, clipHeight)
	oldDrawPosX := drawPosX
	drawPosX += t.textOffset

	if t.committed {
		ctx.Text(drawPosX, drawPosY, t.value)
	} else {
		text := t.editingText()
		textString := string(text)
		_, bounds := ctx.TextBounds(drawPosX, drawPosY, textString)
		lineH := bounds[3] - bounds[1]
		// find cursor positions
		glyphs := ctx.TextGlyphPositionsRune(drawPosX, drawPosY, text)
		t.updateCursor(ctx, bounds[2], glyphs)

		// compute text offset
		prevCPos := toI(t.cursorPos > 0, t.cursorPos-1, 0)
		nextCPos := toI(t.cursorPos < len(glyphs), t.cursorPos+1, len(glyphs))
		prevCX := t.textIndex2Position(prevCPos, bounds[2], glyphs)
		nextCX := t.textIndex2Position(nextCPos, bounds[2], glyphs)

		if nextCX > clipX+clipWidth {
			t.textOffset -= nextCX - (clipX + clipWidth) + 1.0
		}
		if prevCX < clipX {
			t.textOffset += clipX - prevCX + 1.0
		}
		drawPosX = oldDrawPosX + t.textOffset

		// draw text with offset
		ctx.TextRune(drawPosX, drawPosY, text)
		_, bounds = ctx.TextBounds(drawPosX, drawPosY, textString)

		// recompute cursor position
		glyphs = ctx.TextGlyphPositionsRune(drawPosX, drawPosY, text)

		var caretX float32 = -1
		if len(t.preeditText) != 0 {
			// draw preedit text
			caretX = t.textIndex2Position(t.cursorPos+len(t.preeditText), bounds[2], glyphs)

			offsetIndex := t.cursorPos
			offsetX := t.textIndex2Position(t.cursorPos, bounds[2], glyphs)
			ctx.SetStrokeColor(nanovgo.MONO(255, 160))
			ctx.SetFillColor(nanovgo.MONO(255, 80))
			ctx.SetStrokeWidth(2.0)
			for i, blockLength := range t.preeditBlocks {
				nextOffsetIndex := offsetIndex + blockLength
				nextOffsetX := t.textIndex2Position(nextOffsetIndex, bounds[2], glyphs)
				if i != t.preeditFocusedBlock {
					ctx.BeginPath()
					ctx.MoveTo(offsetX+2, drawPosY+lineH*0.5-1)
					ctx.LineTo(nextOffsetX-2, drawPosY+lineH*0.5-1)
					ctx.Stroke()
				} else {
					ctx.BeginPath()
					ctx.Rect(offsetX, drawPosY-lineH*0.5, nextOffsetX-offsetX, lineH)
					ctx.Fill()
				}
				offsetIndex = nextOffsetIndex
				offsetX = nextOffsetX
			}
			screen := t.FindWindow().Parent().(*Screen)
			oldCurX, oldCurY, oldCurH := screen.PreeditCursorPos()
			absX, absY := t.Parent().AbsolutePosition()
			newCurX := int(caretX) + absX
			newCurY := int(drawPosY+lineH*0.5) + absY
			newCurH := int(lineH)
			if oldCurX != newCurX || oldCurY != newCurY || oldCurH != newCurH {
				screen.SetPreeditCursorPos(newCurX, newCurY, newCurH)
			}
		} else if t.cursorPos > -1 {
			// regular cursor and selection area
			caretX = t.textIndex2Position(t.cursorPos, bounds[2], glyphs)

			if t.selectionPos > -1 {
				caretX2 := caretX
				selX := t.textIndex2Position(t.selectionPos, bounds[2], glyphs)

				if caretX2 > selX {
					selX, caretX2 = caretX2, selX
				}

				// draw selection
				ctx.BeginPath()
				ctx.SetFillColor(nanovgo.MONO(255, 80))
				ctx.Rect(caretX2, drawPosY-lineH*0.5, selX-caretX2, lineH)
				ctx.Fill()
			}
		}
		if caretX > 0 {
			// draw cursor
			ctx.BeginPath()
			ctx.MoveTo(caretX, drawPosY-lineH*0.5)
			ctx.LineTo(caretX, drawPosY+lineH*0.5)
			ctx.SetStrokeColor(nanovgo.RGBA(255, 192, 0, 255))
			ctx.SetStrokeWidth(1.0)
			ctx.Stroke()
		}
	}
	ctx.ResetScissor()
}