// Draw draws this primitive onto the screen.
9255
func (t *Table) Draw(screen tcell.Screen) {
	t.Box.Draw(screen)

	// What's our available screen space?
	x, y, width, height := t.GetInnerRect()
	if t.borders {
		t.visibleRows = height / 2
	} else {
		t.visibleRows = height
	}

	// Return the cell at the specified position (nil if it doesn't exist).
	getCell := func(row, column int) *TableCell {
		if row < 0 || column < 0 || row >= len(t.cells) || column >= len(t.cells[row]) {
			return nil
		}
		return t.cells[row][column]
	}

	// If this cell is not selectable, find the next one.
	if t.rowsSelectable || t.columnsSelectable {
		if t.selectedColumn < 0 {
			t.selectedColumn = 0
		}
		if t.selectedRow < 0 {
			t.selectedRow = 0
		}
		for t.selectedRow < len(t.cells) {
			cell := getCell(t.selectedRow, t.selectedColumn)
			if cell == nil || !cell.NotSelectable {
				break
			}
			t.selectedColumn++
			if t.selectedColumn > t.lastColumn {
				t.selectedColumn = 0
				t.selectedRow++
			}
		}
	}

	// Clamp row offsets.
	if t.rowsSelectable {
		if t.selectedRow >= t.fixedRows && t.selectedRow < t.fixedRows+t.rowOffset {
			t.rowOffset = t.selectedRow - t.fixedRows
			t.trackEnd = false
		}
		if t.borders {
			if 2*(t.selectedRow+1-t.rowOffset) >= height {
				t.rowOffset = t.selectedRow + 1 - height/2
				t.trackEnd = false
			}
		} else {
			if t.selectedRow+1-t.rowOffset >= height {
				t.rowOffset = t.selectedRow + 1 - height
				t.trackEnd = false
			}
		}
	}
	if t.borders {
		if 2*(len(t.cells)-t.rowOffset) < height {
			t.trackEnd = true
		}
	} else {
		if len(t.cells)-t.rowOffset < height {
			t.trackEnd = true
		}
	}
	if t.trackEnd {
		if t.borders {
			t.rowOffset = len(t.cells) - height/2
		} else {
			t.rowOffset = len(t.cells) - height
		}
	}
	if t.rowOffset < 0 {
		t.rowOffset = 0
	}

	// Clamp column offset. (Only left side here. The right side is more
	// difficult and we'll do it below.)
	if t.columnsSelectable && t.selectedColumn >= t.fixedColumns && t.selectedColumn < t.fixedColumns+t.columnOffset {
		t.columnOffset = t.selectedColumn - t.fixedColumns
	}
	if t.columnOffset < 0 {
		t.columnOffset = 0
	}
	if t.selectedColumn < 0 {
		t.selectedColumn = 0
	}

	// Determine the indices and widths of the columns and rows which fit on the
	// screen.
	var (
		columns, rows, widths   []int
		tableHeight, tableWidth int
	)
	rowStep := 1
	if t.borders {
		rowStep = 2    // With borders, every table row takes two screen rows.
		tableWidth = 1 // We start at the second character because of the left table border.
	}
	indexRow := func(row int) bool { // Determine if this row is visible, store its index.
		if tableHeight >= height {
			return false
		}
		rows = append(rows, row)
		tableHeight += rowStep
		return true
	}
	for row := 0; row < t.fixedRows && row < len(t.cells); row++ { // Do the fixed rows first.
		if !indexRow(row) {
			break
		}
	}
	for row := t.fixedRows + t.rowOffset; row < len(t.cells); row++ { // Then the remaining rows.
		if !indexRow(row) {
			break
		}
	}
	var (
		skipped, lastTableWidth, expansionTotal int
		expansions                              []int
	)
ColumnLoop:
	for column := 0; ; column++ {
		// If we've moved beyond the right border, we stop or skip a column.
		for tableWidth-1 >= width { // -1 because we include one extra column if the separator falls on the right end of the box.
			// We've moved beyond the available space.
			if column < t.fixedColumns {
				break ColumnLoop // We're in the fixed area. We're done.
			}
			if !t.columnsSelectable && skipped >= t.columnOffset {
				break ColumnLoop // There is no selection and we've already reached the offset.
			}
			if t.columnsSelectable && t.selectedColumn-skipped == t.fixedColumns {
				break ColumnLoop // The selected column reached the leftmost point before disappearing.
			}
			if t.columnsSelectable && skipped >= t.columnOffset &&
				(t.selectedColumn < column && lastTableWidth < width-1 && tableWidth < width-1 || t.selectedColumn < column-1) {
				break ColumnLoop // We've skipped as many as requested and the selection is visible.
			}
			if len(columns) <= t.fixedColumns {
				break // Nothing to skip.
			}

			// We need to skip a column.
			skipped++
			lastTableWidth -= widths[t.fixedColumns] + 1
			tableWidth -= widths[t.fixedColumns] + 1
			columns = append(columns[:t.fixedColumns], columns[t.fixedColumns+1:]...)
			widths = append(widths[:t.fixedColumns], widths[t.fixedColumns+1:]...)
			expansions = append(expansions[:t.fixedColumns], expansions[t.fixedColumns+1:]...)
		}

		// What's this column's width (without expansion)?
		maxWidth := -1
		expansion := 0
		for _, row := range rows {
			if cell := getCell(row, column); cell != nil {
				_, _, _, _, _, _, cellWidth := decomposeString(cell.Text, true, false)
				if cell.MaxWidth > 0 && cell.MaxWidth < cellWidth {
					cellWidth = cell.MaxWidth
				}
				if cellWidth > maxWidth {
					maxWidth = cellWidth
				}
				if cell.Expansion > expansion {
					expansion = cell.Expansion
				}
			}
		}
		if maxWidth < 0 {
			break // No more cells found in this column.
		}

		// Store new column info at the end.
		columns = append(columns, column)
		widths = append(widths, maxWidth)
		lastTableWidth = tableWidth
		tableWidth += maxWidth + 1
		expansions = append(expansions, expansion)
		expansionTotal += expansion
	}
	t.columnOffset = skipped

	// If we have space left, distribute it.
	if tableWidth < width {
		toDistribute := width - tableWidth
		for index, expansion := range expansions {
			if expansionTotal <= 0 {
				break
			}
			expWidth := toDistribute * expansion / expansionTotal
			widths[index] += expWidth
			toDistribute -= expWidth
			expansionTotal -= expansion
		}
	}

	// Helper function which draws border runes.
	borderStyle := tcell.StyleDefault.Background(t.backgroundColor).Foreground(t.bordersColor)
	drawBorder := func(colX, rowY int, ch rune) {
		screen.SetContent(x+colX, y+rowY, ch, nil, borderStyle)
	}

	// Draw the cells (and borders).
	var columnX int
	if !t.borders {
		columnX--
	}
	for columnIndex, column := range columns {
		columnWidth := widths[columnIndex]
		for rowY, row := range rows {
			if t.borders {
				// Draw borders.
				rowY *= 2
				for pos := 0; pos < columnWidth && columnX+1+pos < width; pos++ {
					drawBorder(columnX+pos+1, rowY, Borders.Horizontal)
				}
				ch := Borders.Cross
				if columnIndex == 0 {
					if rowY == 0 {
						ch = Borders.TopLeft
					} else {
						ch = Borders.LeftT
					}
				} else if rowY == 0 {
					ch = Borders.TopT
				}
				drawBorder(columnX, rowY, ch)
				rowY++
				if rowY >= height {
					break // No space for the text anymore.
				}
				drawBorder(columnX, rowY, Borders.Vertical)
			} else if columnIndex > 0 {
				// Draw separator.
				drawBorder(columnX, rowY, t.separator)
			}

			// Get the cell.
			cell := getCell(row, column)
			if cell == nil {
				continue
			}

			// Draw text.
			finalWidth := columnWidth
			if columnX+1+columnWidth >= width {
				finalWidth = width - columnX - 1
			}
			cell.x, cell.y, cell.width = x+columnX+1, y+rowY, finalWidth
			_, printed := printWithStyle(screen, cell.Text, x+columnX+1, y+rowY, finalWidth, cell.Align, tcell.StyleDefault.Foreground(cell.Color)|tcell.Style(cell.Attributes))
			if TaggedStringWidth(cell.Text)-printed > 0 && printed > 0 {
				_, _, style, _ := screen.GetContent(x+columnX+1+finalWidth-1, y+rowY)
				printWithStyle(screen, string(SemigraphicsHorizontalEllipsis), x+columnX+1+finalWidth-1, y+rowY, 1, AlignLeft, style)
			}
		}

		// Draw bottom border.
		if rowY := 2 * len(rows); t.borders && rowY < height {
			for pos := 0; pos < columnWidth && columnX+1+pos < width; pos++ {
				drawBorder(columnX+pos+1, rowY, Borders.Horizontal)
			}
			ch := Borders.BottomT
			if columnIndex == 0 {
				ch = Borders.BottomLeft
			}
			drawBorder(columnX, rowY, ch)
		}

		columnX += columnWidth + 1
	}

	// Draw right border.
	if t.borders && len(t.cells) > 0 && columnX < width {
		for rowY := range rows {
			rowY *= 2
			if rowY+1 < height {
				drawBorder(columnX, rowY+1, Borders.Vertical)
			}
			ch := Borders.RightT
			if rowY == 0 {
				ch = Borders.TopRight
			}
			drawBorder(columnX, rowY, ch)
		}
		if rowY := 2 * len(rows); rowY < height {
			drawBorder(columnX, rowY, Borders.BottomRight)
		}
	}

	// Helper function which colors the background of a box.
	// backgroundColor == tcell.ColorDefault => Don't color the background.
	// textColor == tcell.ColorDefault => Don't change the text color.
	// attr == 0 => Don't change attributes.
	// invert == true => Ignore attr, set text to backgroundColor or t.backgroundColor;
	//                   set background to textColor.
	colorBackground := func(fromX, fromY, w, h int, backgroundColor, textColor tcell.Color, attr tcell.AttrMask, invert bool) {
		for by := 0; by < h && fromY+by < y+height; by++ {
			for bx := 0; bx < w && fromX+bx < x+width; bx++ {
				m, c, style, _ := screen.GetContent(fromX+bx, fromY+by)
				fg, bg, a := style.Decompose()
				if invert {
					if fg == textColor || fg == t.bordersColor {
						fg = backgroundColor
					}
					if fg == tcell.ColorDefault {
						fg = t.backgroundColor
					}
					style = style.Background(textColor).Foreground(fg)
				} else {
					if backgroundColor != tcell.ColorDefault {
						bg = backgroundColor
					}
					if textColor != tcell.ColorDefault {
						fg = textColor
					}
					if attr != 0 {
						a = attr
					}
					style = style.Background(bg).Foreground(fg) | tcell.Style(a)
				}
				screen.SetContent(fromX+bx, fromY+by, m, c, style)
			}
		}
	}

	// Color the cell backgrounds. To avoid undesirable artefacts, we combine
	// the drawing of a cell by background color, selected cells last.
	type cellInfo struct {
		x, y, w, h int
		text       tcell.Color
		selected   bool
	}
	cellsByBackgroundColor := make(map[tcell.Color][]*cellInfo)
	var backgroundColors []tcell.Color
	for rowY, row := range rows {
		columnX := 0
		rowSelected := t.rowsSelectable && !t.columnsSelectable && row == t.selectedRow
		for columnIndex, column := range columns {
			columnWidth := widths[columnIndex]
			cell := getCell(row, column)
			if cell == nil {
				continue
			}
			bx, by, bw, bh := x+columnX, y+rowY, columnWidth+1, 1
			if t.borders {
				by = y + rowY*2
				bw++
				bh = 3
			}
			columnSelected := t.columnsSelectable && !t.rowsSelectable && column == t.selectedColumn
			cellSelected := !cell.NotSelectable && (columnSelected || rowSelected || t.rowsSelectable && t.columnsSelectable && column == t.selectedColumn && row == t.selectedRow)
			entries, ok := cellsByBackgroundColor[cell.BackgroundColor]
			cellsByBackgroundColor[cell.BackgroundColor] = append(entries, &cellInfo{
				x:        bx,
				y:        by,
				w:        bw,
				h:        bh,
				text:     cell.Color,
				selected: cellSelected,
			})
			if !ok {
				backgroundColors = append(backgroundColors, cell.BackgroundColor)
			}
			columnX += columnWidth + 1
		}
	}
	sort.Slice(backgroundColors, func(i int, j int) bool {
		// Draw brightest colors last (i.e. on top).
		r, g, b := backgroundColors[i].RGB()
		c := colorful.Color{R: float64(r) / 255, G: float64(g) / 255, B: float64(b) / 255}
		_, _, li := c.Hcl()
		r, g, b = backgroundColors[j].RGB()
		c = colorful.Color{R: float64(r) / 255, G: float64(g) / 255, B: float64(b) / 255}
		_, _, lj := c.Hcl()
		return li < lj
	})
	selFg, selBg, selAttr := t.selectedStyle.Decompose()
	for _, bgColor := range backgroundColors {
		entries := cellsByBackgroundColor[bgColor]
		for _, cell := range entries {
			if cell.selected {
				if t.selectedStyle != 0 {
					defer colorBackground(cell.x, cell.y, cell.w, cell.h, selBg, selFg, selAttr, false)
				} else {
					defer colorBackground(cell.x, cell.y, cell.w, cell.h, bgColor, cell.text, 0, true)
				}
			} else {
				colorBackground(cell.x, cell.y, cell.w, cell.h, bgColor, tcell.ColorDefault, 0, false)
			}
		}
	}
}
497325
func (d *Drawer) Draw(t Target) {
	d.lazyInit()

	if d.Triangles == nil {
		return
	}

	dt := d.targets[t]
	if dt == nil {
		dt = &drawerTarget{
			pics: make(map[Picture]TargetPicture),
		}
		d.targets[t] = dt
	}

	if dt.tris == nil {
		dt.tris = t.MakeTriangles(d.Triangles)
		dt.clean = true
	}

	if !dt.clean {
		dt.tris.SetLen(d.Triangles.Len())
		dt.tris.Update(d.Triangles)
		dt.clean = true
	}

	if d.Picture == nil {
		dt.tris.Draw()
		return
	}

	pic := dt.pics[d.Picture]
	if pic == nil {
		pic = t.MakePicture(d.Picture)
		dt.pics[d.Picture] = pic
	}

	pic.Draw(dt.tris)
}
785052
func (e *TextEdit) Draw(p *Painter) {
	style := "entry"
	if e.IsFocused() {
		style += ".focused"
	}
	p.WithStyle(style, func(p *Painter) {
		s := e.Size()
		e.text.SetMaxWidth(s.X)

		lines := e.text.SplitByLine()
		for i, line := range lines {
			p.FillRect(0, i, s.X, 1)
			p.DrawText(0, i, line)
		}
		if e.IsFocused() {
			pos := e.text.CursorPos()
			p.DrawCursor(pos.X, pos.Y)
		}
	})
}
164099
func (e *Entry) Draw(p *Painter) {
	style := "entry"
	if e.IsFocused() {
		style += ".focused"
	}
	p.WithStyle(style, func(p *Painter) {
		s := e.Size()
		e.text.SetMaxWidth(s.X)

		text := e.visibleText()

		p.FillRect(0, 0, s.X, 1)

		switch e.echoMode {
		case EchoModeNormal:
			p.DrawText(0, 0, text)
		case EchoModePassword:
			p.DrawText(0, 0, strings.Repeat("*", len(text)))
		}

		if e.IsFocused() {
			var off int
			if e.echoMode != EchoModeNoEcho {
				off = e.text.CursorPos().X - e.offset
			}
			p.DrawCursor(off, 0)
		}
	})
}
814439
func (c *ProgressBar) Draw() {
	// For now, just draw a [####  ] bar
	// TODO: make this more advanced
	useFg := c.fg
	if c.colorized {
		if c.GetPercent() < 10 {
			useFg = termbox.ColorRed
		} else if c.GetPercent() < 50 {
			useFg = termbox.ColorYellow
		} else {
			useFg = termbox.ColorGreen
		}
	}
	drawX, drawY := c.x, c.y
	fillWidth, fillHeight := c.width-2, c.height
	DrawStringAtPoint("[", drawX, drawY, c.fg, c.bg)
	numFull := int(float64(fillWidth) * float64(c.progress) / float64(c.total))
	FillWithChar(c.fullChar, drawX+1, drawY, drawX+1+numFull, drawY+(fillHeight-1), useFg, c.bg)
	DrawStringAtPoint("]", drawX+c.width-1, drawY, c.fg, c.bg)

	/*
		drawX, drawY := c.x, c.y
		drawWidth, drawHeight := c.width, c.height
		if c.bordered {
			if c.height == 1 && c.width > 2 {
				// Just using [ & ] for the border
				DrawStringAtPoint("[", drawX, drawY, c.fg, c.bg)
				DrawStringAtPoint("]", drawX+c.width-1, drawY, c.fg, c.bg)
				drawX++
				drawWidth -= 2
			} else if c.height >= 3 {
				DrawBorder(drawX, drawY, drawX+c.width, drawY+c.height, c.fg, c.bg)
				drawX++
				drawY++
				drawWidth -= 2
				drawHeight -= 2
			}
		}

		// Figure out how many chars are full
		numFull := drawWidth * (c.progress / c.total)
		switch c.alignment {
		case AlignRight: // TODO: Fill from right to left
		case AlignCenter: // TODO: Fill from middle out
		default: // Fill from left to right
			FillWithChar(c.fullChar, drawX, drawY, drawX+numFull, drawY+(drawHeight-1), c.fg, c.bg)
			if numFull < drawWidth {
				FillWithChar(c.emptyChar, drawX+numFull, drawY, drawX+drawWidth-1, drawY+(drawHeight-1), c.fg, c.bg)
			}
		}
	*/
}
452775
func (d *APA102Driver) Draw() error {
	// TODO(jbd): dotstar allows other RGBA alignments, support those layouts.
	n := len(d.vals)

	tx := make([]byte, 4*(n+1)+(n/2+1))
	tx[0] = 0x00
	tx[1] = 0x00
	tx[2] = 0x00
	tx[3] = 0x00

	for i, c := range d.vals {
		j := (i + 1) * 4
		tx[j] = 0xe0 + byte(c.R)
		tx[j+1] = byte(c.B)
		tx[j+2] = byte(c.G)
		tx[j+3] = byte(c.R)
	}

	// end frame with at least n/2 0xff vals
	for i := (n + 1) * 4; i < len(tx); i++ {
		tx[i] = 0xff
	}

	return d.connection.Tx(tx, nil)
}
1302486
func (macdl *MACDLineSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
	style := macdl.Style.InheritFrom(defaults)
	Draw.LineSeries(r, canvasBox, xrange, yrange, style, macdl)
}
8726
func (l *Label) Draw(p *Painter) {
	lines := l.lines()

	style := "label"
	if l.styleName != "" {
		style += "." + l.styleName
	}

	p.WithStyle(style, func(p *Painter) {
		for i, line := range lines {
			p.DrawText(0, i, line)
		}
	})
}
1218680
func (img *Image) DrawCircle(xc, yc, r int, fill bool, c color.Color) {
	size := img.Bounds().Size()
	// 如果圆在图片可见区域外，直接退出
	if xc+r < 0 || xc-r >= size.X || yc+r < 0 || yc-r >= size.Y {
		return
	}
	x, y, d := 0, r, 3-2*r
	for x <= y {
		if fill {
			for yi := x; yi <= y; yi++ {
				img.drawCircle8(xc, yc, x, yi, c)
			}
		} else {
			img.drawCircle8(xc, yc, x, y, c)
		}
		if d < 0 {
			d = d + 4*x + 6
		} else {
			d = d + 4*(x-y) + 10
			y--
		}
		x++
	}
}
1137255
func (g *GIFT) Draw(dst draw.Image, src image.Image) {
	if len(g.Filters) == 0 {
		copyimage(dst, src, &g.Options)
		return
	}

	first, last := 0, len(g.Filters)-1
	var tmpIn image.Image
	var tmpOut draw.Image

	for i, f := range g.Filters {
		if i == first {
			tmpIn = src
		} else {
			tmpIn = tmpOut
		}

		if i == last {
			tmpOut = dst
		} else {
			tmpOut = createTempImage(f.Bounds(tmpIn.Bounds()))
		}

		f.Draw(tmpOut, tmpIn, &g.Options)
	}
}
600878
func (b *BoxLayout) Draw() {

	if b.view == nil {
		return
	}
	if b.changed {
		b.layout()
	}
	b.view.Fill(' ', b.style)
	for i := range b.cells {
		b.cells[i].widget.Draw()
	}
}
996432
func (d draw) Box(r Renderer, b Box, s Style) {
	s.GetFillAndStrokeOptions().WriteToRenderer(r)
	defer r.ResetStyle()

	r.MoveTo(b.Left, b.Top)
	r.LineTo(b.Right, b.Top)
	r.LineTo(b.Right, b.Bottom)
	r.LineTo(b.Left, b.Bottom)
	r.LineTo(b.Left, b.Top)
	r.FillStroke()
}
1155858
func (b *Board) Draw() string {
	s := "\n A B C D E F G H\n"
	for r := 7; r >= 0; r-- {
		s += Rank(r).String()
		for f := 0; f < numOfSquaresInRow; f++ {
			p := b.Piece(getSquare(File(f), Rank(r)))
			if p == NoPiece {
				s += "-"
			} else {
				s += p.String()
			}
			s += " "
		}
		s += "\n"
	}
	return s
}
694247
func drawProgress(win *Window, state nstyle.WidgetStates, style *nstyle.Progress, bounds, scursor rect.Rect, value, maxval int) {
	out := &win.cmds
	if style.DrawBegin != nil {
		style.DrawBegin(out)
	}
	if style.DrawEnd != nil {
		defer style.DrawEnd(out)
	}

	if style.Draw != nil {
		style.Draw(out, state, style, bounds.Rectangle(), scursor.Rectangle(), value, maxval)
		return
	}

	var background *nstyle.Item
	var cursor *nstyle.Item

	/* select correct colors/images to draw */
	if state&nstyle.WidgetStateActive != 0 {
		background = &style.Active
		cursor = &style.CursorActive
	} else if state&nstyle.WidgetStateHovered != 0 {
		background = &style.Hover
		cursor = &style.CursorHover
	} else {
		background = &style.Normal
		cursor = &style.CursorNormal
	}

	/* draw background */
	if background.Type == nstyle.ItemImage {
		out.DrawImage(bounds, background.Data.Image)
	} else {
		out.FillRect(bounds, style.Rounding, background.Data.Color)
	}

	/* draw cursor */
	if cursor.Type == nstyle.ItemImage {
		out.DrawImage(scursor, cursor.Data.Image)
	} else {
		out.FillRect(scursor, style.Rounding, cursor.Data.Color)
	}
	return
}
1168011
func (l *BasicLayout) DrawScreen(state *Peco, options *DrawOptions) {
	if pdebug.Enabled {
		g := pdebug.Marker("BasicLayout.DrawScreen")
		defer g.End()
	}

	perPage := l.linesPerPage()

	if err := l.CalculatePage(state, perPage); err != nil {
		return
	}

	l.DrawPrompt(state)
	l.list.Draw(state, l, perPage, options)

	if err := l.screen.Flush(); err != nil {
		return
	}
}
862291
func (g *Grid) Draw(screen tcell.Screen) {
	g.Box.Draw(screen)
	x, y, width, height := g.GetInnerRect()
	screenWidth, screenHeight := screen.Size()

	// Make a list of items which apply.
	items := make(map[Primitive]*gridItem)
	for _, item := range g.items {
		item.visible = false
		if item.Width <= 0 || item.Height <= 0 || width < item.MinGridWidth || height < item.MinGridHeight {
			continue
		}
		previousItem, ok := items[item.Item]
		if ok && item.Width < previousItem.Width && item.Height < previousItem.Height {
			continue
		}
		items[item.Item] = item
	}

	// How many rows and columns do we have?
	rows := len(g.rows)
	columns := len(g.columns)
	for _, item := range items {
		rowEnd := item.Row + item.Height
		if rowEnd > rows {
			rows = rowEnd
		}
		columnEnd := item.Column + item.Width
		if columnEnd > columns {
			columns = columnEnd
		}
	}
	if rows == 0 || columns == 0 {
		return // No content.
	}

	// Where are they located?
	rowPos := make([]int, rows)
	rowHeight := make([]int, rows)
	columnPos := make([]int, columns)
	columnWidth := make([]int, columns)

	// How much space do we distribute?
	remainingWidth := width
	remainingHeight := height
	proportionalWidth := 0
	proportionalHeight := 0
	for index, row := range g.rows {
		if row > 0 {
			if row < g.minHeight {
				row = g.minHeight
			}
			remainingHeight -= row
			rowHeight[index] = row
		} else if row == 0 {
			proportionalHeight++
		} else {
			proportionalHeight += -row
		}
	}
	for index, column := range g.columns {
		if column > 0 {
			if column < g.minWidth {
				column = g.minWidth
			}
			remainingWidth -= column
			columnWidth[index] = column
		} else if column == 0 {
			proportionalWidth++
		} else {
			proportionalWidth += -column
		}
	}
	if g.borders {
		remainingHeight -= rows + 1
		remainingWidth -= columns + 1
	} else {
		remainingHeight -= (rows - 1) * g.gapRows
		remainingWidth -= (columns - 1) * g.gapColumns
	}
	if rows > len(g.rows) {
		proportionalHeight += rows - len(g.rows)
	}
	if columns > len(g.columns) {
		proportionalWidth += columns - len(g.columns)
	}

	// Distribute proportional rows/columns.
	gridWidth := 0
	gridHeight := 0
	for index := 0; index < rows; index++ {
		row := 0
		if index < len(g.rows) {
			row = g.rows[index]
		}
		if row > 0 {
			if row < g.minHeight {
				row = g.minHeight
			}
			gridHeight += row
			continue // Not proportional. We already know the width.
		} else if row == 0 {
			row = 1
		} else {
			row = -row
		}
		rowAbs := row * remainingHeight / proportionalHeight
		remainingHeight -= rowAbs
		proportionalHeight -= row
		if rowAbs < g.minHeight {
			rowAbs = g.minHeight
		}
		rowHeight[index] = rowAbs
		gridHeight += rowAbs
	}
	for index := 0; index < columns; index++ {
		column := 0
		if index < len(g.columns) {
			column = g.columns[index]
		}
		if column > 0 {
			if column < g.minWidth {
				column = g.minWidth
			}
			gridWidth += column
			continue // Not proportional. We already know the height.
		} else if column == 0 {
			column = 1
		} else {
			column = -column
		}
		columnAbs := column * remainingWidth / proportionalWidth
		remainingWidth -= columnAbs
		proportionalWidth -= column
		if columnAbs < g.minWidth {
			columnAbs = g.minWidth
		}
		columnWidth[index] = columnAbs
		gridWidth += columnAbs
	}
	if g.borders {
		gridHeight += rows + 1
		gridWidth += columns + 1
	} else {
		gridHeight += (rows - 1) * g.gapRows
		gridWidth += (columns - 1) * g.gapColumns
	}

	// Calculate row/column positions.
	columnX, rowY := x, y
	if g.borders {
		columnX++
		rowY++
	}
	for index, row := range rowHeight {
		rowPos[index] = rowY
		gap := g.gapRows
		if g.borders {
			gap = 1
		}
		rowY += row + gap
	}
	for index, column := range columnWidth {
		columnPos[index] = columnX
		gap := g.gapColumns
		if g.borders {
			gap = 1
		}
		columnX += column + gap
	}

	// Calculate primitive positions.
	var focus *gridItem // The item which has focus.
	for primitive, item := range items {
		px := columnPos[item.Column]
		py := rowPos[item.Row]
		var pw, ph int
		for index := 0; index < item.Height; index++ {
			ph += rowHeight[item.Row+index]
		}
		for index := 0; index < item.Width; index++ {
			pw += columnWidth[item.Column+index]
		}
		if g.borders {
			pw += item.Width - 1
			ph += item.Height - 1
		} else {
			pw += (item.Width - 1) * g.gapColumns
			ph += (item.Height - 1) * g.gapRows
		}
		item.x, item.y, item.w, item.h = px, py, pw, ph
		item.visible = true
		if primitive.GetFocusable().HasFocus() {
			focus = item
		}
	}

	// Calculate screen offsets.
	var offsetX, offsetY, add int
	if g.rowOffset < 0 {
		g.rowOffset = 0
	}
	if g.columnOffset < 0 {
		g.columnOffset = 0
	}
	if g.borders {
		add = 1
	}
	for row := 0; row < rows-1; row++ {
		remainingHeight := gridHeight - offsetY
		if focus != nil && focus.y-add <= offsetY || // Don't let the focused item move out of screen.
			row >= g.rowOffset && (focus == nil || focus != nil && focus.y-offsetY < height) || // We've reached the requested offset.
			remainingHeight <= height { // We have enough space to show the rest.
			if row > 0 {
				if focus != nil && focus.y+focus.h+add-offsetY > height {
					offsetY += focus.y + focus.h + add - offsetY - height
				}
				if remainingHeight < height {
					offsetY = gridHeight - height
				}
			}
			g.rowOffset = row
			break
		}
		offsetY = rowPos[row+1] - add
	}
	for column := 0; column < columns-1; column++ {
		remainingWidth := gridWidth - offsetX
		if focus != nil && focus.x-add <= offsetX || // Don't let the focused item move out of screen.
			column >= g.columnOffset && (focus == nil || focus != nil && focus.x-offsetX < width) || // We've reached the requested offset.
			remainingWidth <= width { // We have enough space to show the rest.
			if column > 0 {
				if focus != nil && focus.x+focus.w+add-offsetX > width {
					offsetX += focus.x + focus.w + add - offsetX - width
				} else if remainingWidth < width {
					offsetX = gridWidth - width
				}
			}
			g.columnOffset = column
			break
		}
		offsetX = columnPos[column+1] - add
	}

	// Draw primitives and borders.
	for primitive, item := range items {
		// Final primitive position.
		if !item.visible {
			continue
		}
		item.x -= offsetX
		item.y -= offsetY
		if item.x+item.w > x+width {
			item.w = width - item.x
		}
		if item.y+item.h > y+height {
			item.h = height - item.y
		}
		if item.x < 0 {
			item.w += item.x
			item.x = 0
		}
		if item.y < 0 {
			item.h += item.y
			item.y = 0
		}
		if item.w <= 0 || item.h <= 0 {
			item.visible = false
			continue
		}
		primitive.SetRect(item.x, item.y, item.w, item.h)

		// Draw primitive.
		if item == focus {
			defer primitive.Draw(screen)
		} else {
			primitive.Draw(screen)
		}

		// Draw border around primitive.
		if g.borders {
			for bx := item.x; bx < item.x+item.w; bx++ { // Top/bottom lines.
				if bx < 0 || bx >= screenWidth {
					continue
				}
				by := item.y - 1
				if by >= 0 && by < screenHeight {
					PrintJoinedSemigraphics(screen, bx, by, Borders.Horizontal, g.bordersColor)
				}
				by = item.y + item.h
				if by >= 0 && by < screenHeight {
					PrintJoinedSemigraphics(screen, bx, by, Borders.Horizontal, g.bordersColor)
				}
			}
			for by := item.y; by < item.y+item.h; by++ { // Left/right lines.
				if by < 0 || by >= screenHeight {
					continue
				}
				bx := item.x - 1
				if bx >= 0 && bx < screenWidth {
					PrintJoinedSemigraphics(screen, bx, by, Borders.Vertical, g.bordersColor)
				}
				bx = item.x + item.w
				if bx >= 0 && bx < screenWidth {
					PrintJoinedSemigraphics(screen, bx, by, Borders.Vertical, g.bordersColor)
				}
			}
			bx, by := item.x-1, item.y-1 // Top-left corner.
			if bx >= 0 && bx < screenWidth && by >= 0 && by < screenHeight {
				PrintJoinedSemigraphics(screen, bx, by, Borders.TopLeft, g.bordersColor)
			}
			bx, by = item.x+item.w, item.y-1 // Top-right corner.
			if bx >= 0 && bx < screenWidth && by >= 0 && by < screenHeight {
				PrintJoinedSemigraphics(screen, bx, by, Borders.TopRight, g.bordersColor)
			}
			bx, by = item.x-1, item.y+item.h // Bottom-left corner.
			if bx >= 0 && bx < screenWidth && by >= 0 && by < screenHeight {
				PrintJoinedSemigraphics(screen, bx, by, Borders.BottomLeft, g.bordersColor)
			}
			bx, by = item.x+item.w, item.y+item.h // Bottom-right corner.
			if bx >= 0 && bx < screenWidth && by >= 0 && by < screenHeight {
				PrintJoinedSemigraphics(screen, bx, by, Borders.BottomRight, g.bordersColor)
			}
		}
	}
}
188440
func (p *Painter) DrawRune(x, y int, r rune) {
	wp := p.mapLocalToWorld(image.Point{x, y})
	if (p.mask.Min.X <= wp.X) && (wp.X < p.mask.Max.X) && (p.mask.Min.Y <= wp.Y) && (wp.Y < p.mask.Max.Y) {
		p.surface.SetCell(wp.X, wp.Y, r, p.style)
	}
}