Пример #1
0
// NewEditField creates a new EditField control
// view - is a View that manages the control
// parent - is container that keeps the control. The same View can be a view and a parent at the same time.
// width - is minimal width of the control.
// text - text to edit.
// scale - the way of scaling the control when the parent is resized. Use DoNotScale constant if the
//  control should keep its original size.
func CreateEditField(parent Control, width int, text string, scale int) *EditField {
	e := new(EditField)
	e.onChange = nil
	e.SetTitle(text)
	e.SetEnabled(true)

	if width == AutoSize {
		width = xs.Len(text) + 1
	}

	e.SetSize(width, 1)
	e.cursorPos = xs.Len(text)
	e.offset = 0
	e.parent = parent
	e.parent = parent
	e.readonly = false
	e.SetScale(scale)

	e.SetConstraints(width, 1)

	e.end()

	if parent != nil {
		parent.AddChild(e)
	}

	return e
}
Пример #2
0
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++
		}
	}
}
Пример #3
0
func enginePost(blogPosts map[string]*BlogPost, href string, whenDone chan bool) {
	doc, err := goquery.NewDocument(appConfiguration["website_root"].StringValue + href)

	if err != nil {
		fmt.Printf("Impossible to reach %s\n", href)
		whenDone <- false
		return
	}

	author := strings.Trim(doc.Find(".james-author").Text(), " \n")
	headline := strings.Trim(doc.Find(".james-headline").Text(), " \n")
	text := doc.Find(".james-content").Text()
	timestamp, _ := doc.Find(".james-date").Attr("data-timestamp")
	parsedTime, _ := strconv.ParseInt(timestamp, 10, 64)
	hash := make(map[string]int)

	post := BlogPost{
		href,
		author,
		headline,
		time.Unix(parsedTime, 0),
		hash,
		"",
	}

	buffer := ""
	words := 0
	for i := 0; i < xstrings.Len(text); i++ {
		c := string(text[i])
		if isMatching, _ := regexp.MatchString("[a-zA-Z0-9]", c); isMatching == true {
			buffer += c
		} else if buffer != "" {
			if xstrings.Len(buffer) >= appConfiguration["min_word_length"].IntValue {
				buffer = strings.ToLower(buffer)
				e, exists := hash[buffer]
				if exists {
					hash[buffer] = e + 1
				} else {
					hash[buffer] = 1
				}
			}

			if words < appConfiguration["brief_number_of_words"].IntValue {
				if words > 0 {
					post.Brief += " "
				}
				post.Brief += buffer
				words++
			}

			buffer = ""
		}
	}

	blogPosts[href] = &post

	whenDone <- true
}
Пример #4
0
// 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)
	}
}
Пример #5
0
func (l *TextView) calculateVirtualSize() {
	w := l.width - 1
	l.virtualWidth = l.width - 1
	l.virtualHeight = 0

	l.lengths = make([]int, len(l.lines))
	for idx, str := range l.lines {
		str = UnColorizeText(str)

		sz := xs.Len(str)
		if l.wordWrap {
			n := sz / w
			r := sz % w
			l.virtualHeight += n
			if r != 0 {
				l.virtualHeight++
			}
		} else {
			l.virtualHeight++
			if sz > l.virtualWidth {
				l.virtualWidth = sz
			}
		}
		l.lengths[idx] = sz
	}
}
Пример #6
0
/*
NewButton creates a new Button.
view - is a View that manages the control
parent - is container that keeps the control. The same View can be a view and a parent at the same time.
width and heigth - are minimal size of the control.
title - button title.
scale - the way of scaling the control when the parent is resized. Use DoNotScale constant if the
control should keep its original size.
*/
func CreateButton(parent Control, width, height int, title string, scale int) *Button {
	b := new(Button)

	b.parent = parent
	b.align = AlignCenter

	if height == AutoSize {
		height = 4
	}
	if width == AutoSize {
		width = xs.Len(title) + 2 + 1
	}

	if height < 4 {
		height = 4
	}
	if width < 6 {
		width = 6
	}

	b.SetTitle(title)
	b.SetSize(width, height)
	b.SetConstraints(width, height)
	b.SetScale(scale)

	if parent != nil {
		parent.AddChild(b)
	}

	return b
}
Пример #7
0
// Repaint draws the control on its View surface
func (f *Frame) Draw() {
	PushAttributes()
	defer PopAttributes()

	if f.border == BorderNone {
		f.DrawChildren()
		return
	}

	x, y := f.Pos()
	w, h := f.Size()

	fg, bg := RealColor(f.fg, ColorViewText), RealColor(f.bg, ColorViewBack)

	SetTextColor(fg)
	SetBackColor(bg)
	DrawFrame(x, y, w, h, f.border)

	if f.title != "" {
		str := f.title
		raw := UnColorizeText(str)
		if xs.Len(raw) > w-2 {
			str = SliceColorized(str, 0, w-2-3) + "..."
		}
		DrawText(x+1, y, str)
	}

	f.DrawChildren()
}
Пример #8
0
// 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()
	}
}
Пример #9
0
// 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)
}
Пример #10
0
func (e *EditField) end() {
	length := xs.Len(e.title)
	e.cursorPos = length

	if length < e.width {
		return
	}

	e.offset = length - (e.width - 2)
}
Пример #11
0
// AlignColorizedText does the same as AlignText does but
// it preserves the color of the letters by adding correct
// color tags to the line beginning.
// Note: function is ineffective and a bit slow - do not use
// it everywhere
func AlignColorizedText(str string, width int, align Align) (int, string) {
	rawText := UnColorizeText(str)
	length := xs.Len(rawText)

	if length <= width {
		shift, _ := AlignText(rawText, width, align)
		return shift, str
	}

	skip := 0
	if align == AlignRight {
		skip = length - width
	} else if align == AlignCenter {
		skip = (length - width) / 2
	}

	fgChanged, bgChanged := false, false
	curr := 0
	parser := NewColorParser(str, term.ColorBlack, term.ColorBlack)
	out := ""
	for curr < skip+width {
		elem := parser.NextElement()

		if elem.Type == ElemEndOfText {
			break
		}

		if elem.Type == ElemPrintable {
			curr++
			if curr == skip+1 {
				if fgChanged {
					out += "<t:" + ColorToString(elem.Fg) + ">"
				}
				if bgChanged {
					out += "<b:" + ColorToString(elem.Bg) + ">"
				}
				out += string(elem.Ch)
			} else if curr > skip+1 {
				out += string(elem.Ch)
			}
		} else if elem.Type == ElemTextColor {
			fgChanged = true
			if curr > skip+1 {
				out += "<t:" + ColorToString(elem.Fg) + ">"
			}
		} else if elem.Type == ElemBackColor {
			bgChanged = true
			if curr > skip+1 {
				out += "<b:" + ColorToString(elem.Bg) + ">"
			}
		}
	}

	return 0, out
}
Пример #12
0
func (e *EditField) charRight() {
	length := xs.Len(e.title)
	if e.cursorPos == length || e.title == "" {
		return
	}

	e.cursorPos++
	if e.cursorPos != length && e.cursorPos >= e.offset+e.width-2 {
		e.offset++
	}
}
Пример #13
0
// 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)
}
Пример #14
0
// AlignText calculates the initial position of the text
// output depending on str length and available width.
// The str is truncated in case of its lenght greater than
// width. Function returns shift that should be added to
// original label position before output instead of padding
// the string with spaces. The reason is to make possible
// to draw a label aligned but with transparent beginning
// and ending. If you do not need transparency you can
// add spaces manually using the returned shift value
func AlignText(str string, width int, align Align) (shift int, out string) {
	length := xs.Len(str)

	if length >= width {
		return 0, CutText(str, width)
	}

	if align == AlignRight {
		return width - length, str
	} else if align == AlignCenter {
		return (width - length) / 2, str
	}

	return 0, str
}
Пример #15
0
func compareWords(input string, reference string) float64 {
	var s int
	var prev1 string
	var prev2 string
	score := 0.0

	s1 := xstrings.Len(input)
	s2 := xstrings.Len(reference)
	if s1 < s2 {
		s = s1
	} else {
		s = s2
	}

	for i := 0; i < s; i++ {
		a := string(input[i])
		b := string(reference[i])

		if i > 0 {
			if prev1 == prev2 && a == b {
				score += 1
			} else if prev1 == b && prev2 == a {
				score += 0.9
			} else if prev1 == prev2 || a == b {
				score += 0.75
			}
		}

		prev1 = a
		prev2 = b
	}

	score /= float64(s1 - 1)

	return score
}
Пример #16
0
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
	}
}
Пример #17
0
func (wnd *Window) drawTitle() {
	PushAttributes()
	defer PopAttributes()

	btnCount := wnd.buttonCount()
	maxw := wnd.width - 2 - btnCount
	if btnCount > 0 {
		maxw -= 2
	}

	fitTitle := wnd.title
	rawText := UnColorizeText(fitTitle)
	if xs.Len(rawText) > maxw {
		fitTitle = SliceColorized(fitTitle, 0, maxw-3) + "..."
	}

	DrawText(wnd.x+1, wnd.y, fitTitle)
}
Пример #18
0
/*
NewRadio creates a new radio button.
view - is a View that manages the control
parent - is container that keeps the control. The same View can be a view and a parent at the same time.
width - is minimal width of the control.
title - radio title.
scale - the way of scaling the control when the parent is resized. Use DoNotScale constant if the
control should keep its original size.
*/
func CreateRadio(parent Control, width int, title string, scale int) *Radio {
	c := new(Radio)

	if width == AutoSize {
		width = xs.Len(title) + 4
	}

	c.parent = parent

	c.SetSize(width, 1) // TODO: only one line heigth is supported at that moment
	c.SetConstraints(width, 1)
	c.SetTitle(title)
	c.SetTabStop(true)
	c.SetScale(scale)

	if parent != nil {
		parent.AddChild(c)
	}

	return c
}
Пример #19
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
	}
}
Пример #20
0
/*
CreateCheckBox creates a new CheckBox control.
parent - is container that keeps the control. The same View can be a view and a parent at the same time.
width - is minimal width of the control.
title - button title.
scale - the way of scaling the control when the parent is resized. Use DoNotScale constant if the
control should keep its original size.
CheckBox state can be changed using mouse or pressing space on keyboard while the control is active
*/
func CreateCheckBox(parent Control, width int, title string, scale int) *CheckBox {
	c := new(CheckBox)
	c.parent = parent

	if width == AutoSize {
		width = xs.Len(title) + 4
	}

	c.SetSize(width, 1) // TODO: only one line checkboxes are supported at that moment
	c.SetConstraints(width, 1)
	c.state = 0
	c.SetTitle(title)
	c.SetTabStop(true)
	c.allow3state = false
	c.onChange = nil
	c.SetScale(scale)

	if parent != nil {
		parent.AddChild(c)
	}

	return c
}
Пример #21
0
/*
NewLabel creates a new label.
view - is a View that manages the control
parent - is container that keeps the control. The same View can be a view and a parent at the same time.
w and h - are minimal size of the control.
title - is Label title.
scale - the way of scaling the control when the parent is resized. Use DoNotScale constant if the
control should keep its original size.
*/
func CreateLabel(parent Control, w, h int, title string, scale int) *Label {
	c := new(Label)

	if w == AutoSize {
		w = xs.Len(title)
	}
	if h == AutoSize {
		h = 1
	}

	c.parent = parent

	c.SetTitle(title)
	c.SetSize(w, h)
	c.SetConstraints(w, h)
	c.SetScale(scale)
	c.tabSkip = true

	if parent != nil {
		parent.AddChild(c)
	}

	return c
}
Пример #22
0
// 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++
	}
}
Пример #23
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++
	}
}
Пример #24
0
// 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)
		}
	}
}
Пример #25
0
func (b *BarChart) drawBars() {
	if len(b.data) == 0 {
		return
	}

	start, width := b.calculateBarArea()
	if width < 2 {
		return
	}

	barW := b.calculateBarWidth()
	if barW == 0 {
		return
	}

	coeff, max := b.calculateMultiplier()
	if coeff == 0.0 {
		return
	}

	PushAttributes()
	defer PopAttributes()

	h := b.barHeight()
	pos := start
	parts := []rune(SysObject(ObjBarChart))
	fg, bg := TextColor(), BackColor()

	for idx, d := range b.data {
		if pos+barW > start+width {
			break
		}

		fColor, bColor := d.Fg, d.Bg
		ch := d.Ch
		if fColor == ColorDefault {
			fColor = fg
		}
		if bColor == ColorDefault {
			bColor = bg
		}
		if ch == 0 {
			ch = parts[0]
		}

		barH := int(d.Value * coeff)
		if b.onDrawCell == nil {
			SetTextColor(fColor)
			SetBackColor(bColor)
			FillRect(b.x+pos, b.y+h-barH, barW, barH, ch)
		} else {
			cellDef := BarDataCell{Item: d.Title, ID: idx,
				Value: 0, BarMax: d.Value, TotalMax: max,
				Fg: fColor, Bg: bColor, Ch: ch}
			for dy := 0; dy < barH; dy++ {
				req := cellDef
				req.Value = max * float64(dy+1) / float64(h)
				b.onDrawCell(&req)
				SetTextColor(req.Fg)
				SetBackColor(req.Bg)
				for dx := 0; dx < barW; dx++ {
					PutChar(b.x+pos+dx, b.y+h-1-dy, req.Ch)
				}
			}
		}

		if b.showTitles {
			SetTextColor(fg)
			SetBackColor(bg)
			if b.showMarks {
				c := parts[7]
				PutChar(b.x+pos+barW/2, b.y+h, c)
			}
			var s string
			shift := 0
			if xs.Len(d.Title) > barW {
				s = CutText(d.Title, barW)
			} else {
				shift, s = AlignText(d.Title, barW, AlignCenter)
			}
			DrawRawText(b.x+pos+shift, b.y+h+1, s)
		}

		pos += barW + b.gap
	}
}