func (e *EditField) insertRune(ch rune) { if e.readonly { return } if e.maxWidth > 0 && xs.Len(e.title) >= e.maxWidth { return } idx := e.cursorPos if idx == 0 { e.SetTitle(string(ch) + e.title) } else if idx >= xs.Len(e.title) { e.SetTitle(e.title + string(ch)) } else { e.SetTitle(xs.Slice(e.title, 0, idx) + string(ch) + xs.Slice(e.title, idx, -1)) } e.cursorPos++ if e.cursorPos >= e.width { if e.offset == 0 { e.offset = 2 } else { e.offset++ } } }
// Ellipsize truncates text to maxWidth by replacing a // substring in the middle with ellipsis and keeping // the beginning and ending of the string untouched. // If maxWidth is less than 5 then no ellipsis is // added, the text is just truncated from the right. func Ellipsize(str string, maxWidth int) string { ln := xs.Len(str) if ln <= maxWidth { return str } if maxWidth < 5 { return xs.Slice(str, 0, maxWidth) } left := int((maxWidth - 3) / 2) right := maxWidth - left - 3 return xs.Slice(str, 0, left) + "..." + xs.Slice(str, ln-right, -1) }
// Repaint draws the control on its View surface func (e *EditField) Draw() { PushAttributes() defer PopAttributes() x, y := e.Pos() w, _ := e.Size() parts := []rune(SysObject(ObjEdit)) chLeft, chRight := string(parts[0]), string(parts[1]) var textOut string curOff := 0 if e.offset == 0 && xs.Len(e.title) < e.width { textOut = e.title } else { fromIdx := 0 toIdx := 0 if e.offset == 0 { toIdx = e.width - 1 textOut = xs.Slice(e.title, 0, toIdx) + chRight curOff = -e.offset } else { curOff = 1 - e.offset fromIdx = e.offset if e.width-1 <= xs.Len(e.title)-e.offset { toIdx = e.offset + e.width - 2 textOut = chLeft + xs.Slice(e.title, fromIdx, toIdx) + chRight } else { textOut = chLeft + xs.Slice(e.title, fromIdx, -1) } } } fg, bg := RealColor(e.fg, ColorEditText), RealColor(e.bg, ColorEditBack) if !e.Enabled() { fg, bg = RealColor(e.fg, ColorDisabledText), RealColor(e.fg, ColorDisabledBack) } else if e.Active() { fg, bg = RealColor(e.fg, ColorEditActiveText), RealColor(e.bg, ColorEditActiveBack) } SetTextColor(fg) SetBackColor(bg) FillRect(x, y, w, 1, ' ') DrawRawText(x, y, textOut) if e.Active() { SetCursorPos(e.cursorPos+e.x+curOff, e.y) } }
// SetMaxWidth sets the maximum lenght of the EditField text. If the current text is longer it is truncated func (e *EditField) SetMaxWidth(w int) { e.maxWidth = w if w > 0 && xs.Len(e.title) > w { e.title = xs.Slice(e.title, 0, w) e.end() } }
// CutText makes a text no longer than maxWidth func CutText(str string, maxWidth int) string { ln := xs.Len(str) if ln <= maxWidth { return str } return xs.Slice(str, 0, maxWidth) }
func (e *EditField) del() { length := xs.Len(e.title) if e.title == "" || e.cursorPos == length || e.readonly { return } if e.cursorPos == length-1 { e.SetTitle(xs.Slice(e.title, 0, length-1)) } else { e.SetTitle(xs.Slice(e.title, 0, e.cursorPos) + xs.Slice(e.title, e.cursorPos+1, -1)) } if length-1 < e.width { e.offset = 0 } }
func (e *EditField) backspace() { if e.title == "" || e.cursorPos == 0 || e.readonly { return } length := xs.Len(e.title) if e.cursorPos >= length { e.cursorPos-- e.SetTitle(xs.Slice(e.title, 0, length-1)) } else if e.cursorPos == 1 { e.cursorPos = 0 e.SetTitle(xs.Slice(e.title, 1, -1)) e.offset = 0 } else { e.cursorPos-- e.SetTitle(xs.Slice(e.title, 0, e.cursorPos) + xs.Slice(e.title, e.cursorPos+1, -1)) } if length-1 < e.width { e.offset = 0 } }
// DrawRawTextVertical draws the part of text that is inside the current clipping // rectangle. DrawRawTextVertical always paints string as is - no color changes. // If you want to draw string with color changing commands included then // use DrawTextVertical function func DrawRawTextVertical(x, y int, text string) { cx, cy, cw, ch := ClipRect() if y >= cy+ch || x < cx || x >= cx+cw { return } length := xs.Len(text) if y+length < cy { return } if y < cy { text = xs.Slice(text, cy-y, -1) length = length - (cy - y) y = cy } text = CutText(text, ch) dy := 0 for _, ch := range text { putCharUnsafe(x, y+dy, ch) dy++ } }
// DrawRawText draws the part of text that is inside the current clipping // rectangle. DrawRawText always paints string as is - no color changes. // If you want to draw string with color changing commands included then // use DrawText function func DrawRawText(x, y int, text string) { cx, cy, cw, ch := ClipRect() if x >= cx+cw || y < cy || y >= cy+ch { return } length := xs.Len(text) if x+length < cx { return } if x < cx { text = xs.Slice(text, cx-x, -1) length = length - (cx - x) x = cx } text = CutText(text, cw) dx := 0 for _, ch := range text { putCharUnsafe(x+dx, y, ch) dx++ } }
// Repaint draws the control on its View surface. // Horizontal ProgressBar supports custom title over the bar. // One can set title using method SetTitle. There are a few // predefined variables that can be used inside title to // show value or total progress. Variable must be enclosed // with double curly brackets. Available variables: // percent - the current percentage rounded to closest integer // value - raw ProgressBar value // min - lower ProgressBar limit // max - upper ProgressBar limit // Examples: // pb.SetTitle("{{value}} of {{max}}") // pb.SetTitle("{{percent}}%") func (b *ProgressBar) Draw() { if b.max <= b.min { return } PushAttributes() defer PopAttributes() fgOff, fgOn := RealColor(b.fg, ColorProgressText), RealColor(b.fgActive, ColorProgressActiveText) bgOff, bgOn := RealColor(b.bg, ColorProgressBack), RealColor(b.bgActive, ColorProgressActiveBack) parts := []rune(SysObject(ObjProgressBar)) cFilled, cEmpty := parts[0], parts[1] prc := 0 if b.value >= b.max { prc = 100 } else if b.value < b.max && b.value > b.min { prc = (100 * (b.value - b.min)) / (b.max - b.min) } var title string if b.direction == Horizontal && b.Title() != "" { title = b.Title() title = strings.Replace(title, "{{percent}}", strconv.Itoa(prc), -1) title = strings.Replace(title, "{{value}}", strconv.Itoa(b.value), -1) title = strings.Replace(title, "{{min}}", strconv.Itoa(b.min), -1) title = strings.Replace(title, "{{max}}", strconv.Itoa(b.max), -1) } x, y := b.Pos() w, h := b.Size() if b.direction == Horizontal { filled := prc * w / 100 sFilled := strings.Repeat(string(cFilled), filled) sEmpty := strings.Repeat(string(cEmpty), w-filled) for yy := y; yy < y+h; yy++ { SetTextColor(fgOn) SetBackColor(bgOn) DrawRawText(x, yy, sFilled) SetTextColor(fgOff) SetBackColor(bgOff) DrawRawText(x+filled, yy, sEmpty) } if title != "" { shift, str := AlignText(title, w, b.align) titleClr := RealColor(b.titleFg, ColorProgressTitleText) var sOn, sOff string if filled == 0 || shift >= filled { sOff = str } else if w == filled || shift+xs.Len(str) < filled { sOn = str } else { r := filled - shift sOn = xs.Slice(str, 0, r) sOff = xs.Slice(str, r, -1) } SetTextColor(titleClr) if sOn != "" { SetBackColor(bgOn) DrawRawText(x+shift, y, sOn) } if sOff != "" { SetBackColor(bgOff) DrawRawText(x+shift+xs.Len(sOn), y, sOff) } } } else { filled := prc * h / 100 sFilled := strings.Repeat(string(cFilled), w) sEmpty := strings.Repeat(string(cEmpty), w) for yy := y; yy < y+h-filled; yy++ { SetTextColor(fgOff) SetBackColor(bgOff) DrawRawText(x, yy, sEmpty) } for yy := y + h - filled; yy < y+h; yy++ { SetTextColor(fgOff) SetBackColor(bgOff) DrawRawText(x, yy, sFilled) } } }