Update vendored dependencies

Signed-off-by: Leandro Dorileo <leandro.maciel.dorileo@intel.com>
This commit is contained in:
Leandro Dorileo
2018-09-07 10:58:40 -07:00
committed by Leandro Dorileo
parent 1866154f30
commit 9b25313e8e
26 changed files with 408 additions and 88 deletions
Generated
+5 -5
View File
@@ -3,11 +3,11 @@
[[projects]]
branch = "master"
digest = "1:06cb27109f9e5ae9e844ccd7527ce1e698caca6b427d088ea43ff1fc91c8ab1c"
digest = "1:cf90665ea4bb37bee01cbecff0a5b2e3b49355a62bfb7dd4aa5433eda11682b5"
name = "github.com/VladimirMarkelov/clui"
packages = ["."]
pruneopts = "UT"
revision = "7749b2936744140b703023c6c9d76491e3abd22c"
revision = "89a7c86623ec35323906bc09de4f1d98bc75abdb"
[[projects]]
digest = "1:dd1417c60900a2be6d1653e90306614657761fc9c3066eccc558ae432b31aa60"
@@ -18,12 +18,12 @@
version = "v0.1.0"
[[projects]]
digest = "1:4e0aa2a8f7c5d6e125af6ed331f5389003429e4fb0747f6d4be9715f246800f0"
digest = "1:f9a5e090336881be43cfc1cf468330c1bdd60abdc9dd194e0b1ab69f4b94dd7c"
name = "github.com/huandu/xstrings"
packages = ["."]
pruneopts = "UT"
revision = "55ae428c2ac4f74d7430952ef528631e656ac92c"
version = "v1.1.0"
revision = "f02667b379e2fb5916c3cda2cf31e0eb885d79f8"
version = "v1.2.0"
[[projects]]
digest = "1:cdb899c199f907ac9fb50495ec71212c95cb5b0e0a8ee0800da0238036091033"
+2 -1
View File
@@ -7,7 +7,7 @@ Command Line User Interface (Console UI inspired by TurboVision) with built-in t
## Current version
The current version is 0.9.0 RC2. Please see details in [changelog](./changelog).
The current version is 0.9.0 RC3. Please see details in [changelog](./changelog).
## Applications that uses the library
* Terminal FB2 reader(termfb2): https://github.com/VladimirMarkelov/termfb2
@@ -40,6 +40,7 @@ The current version is 0.9.0 RC2. Please see details in [changelog](./changelog)
* GridView (Table to show structured data - only virtual and readonly mode with scroll support)
* [FilePicker](/docs/fselect.md)
* LoginDialog - a simple authorization dialog with two fields: Username and Password
* Scrollable frame
## Screenshots
The main demo (theme changing and radio group control)
+1 -1
View File
@@ -1 +1 @@
0.8.1
0.9.0-rc3
+2 -2
View File
@@ -117,7 +117,7 @@ func (b *BarChart) Draw() {
PushAttributes()
defer PopAttributes()
fg, bg := RealColor(b.fg, ColorBarChartText), RealColor(b.bg, ColorBarChartBack)
fg, bg := RealColor(b.fg, b.Style(), ColorBarChartText), RealColor(b.bg, b.Style(), ColorBarChartBack)
SetTextColor(fg)
SetBackColor(bg)
@@ -235,7 +235,7 @@ func (b *BarChart) drawLegend() {
PushAttributes()
defer PopAttributes()
fg, bg := RealColor(b.fg, ColorBarChartText), RealColor(b.bg, ColorBarChartBack)
fg, bg := RealColor(b.fg, b.Style(), ColorBarChartText), RealColor(b.bg, b.Style(), ColorBarChartBack)
parts := []rune(SysObject(ObjBarChart))
defRune := parts[0]
+69 -3
View File
@@ -32,6 +32,9 @@ type BaseControl struct {
children []Control
mtx sync.RWMutex
onActive func(active bool)
style string
clipped bool
clipper *rect
}
var (
@@ -46,6 +49,22 @@ func NewBaseControl() BaseControl {
return BaseControl{refID: nextRefId()}
}
func (c *BaseControl) SetClipped(clipped bool) {
c.clipped = clipped
}
func (c *BaseControl) Clipped() bool {
return c.clipped
}
func (c *BaseControl) SetStyle(style string) {
c.style = style
}
func (c *BaseControl) Style() string {
return c.style
}
func (c *BaseControl) RefID() int64 {
return c.refID
}
@@ -81,8 +100,22 @@ func (c *BaseControl) Pos() (x int, y int) {
}
func (c *BaseControl) SetPos(x, y int) {
c.x = x
c.y = y
if c.clipped && c.clipper != nil {
cx, cy, _, _ := c.Clipper()
px, py := c.Paddings()
distX := cx - c.x
distY := cy - c.y
c.clipper.x = x + px
c.clipper.y = y + py
c.x = (x - distX) + px
c.y = (y - distY) + py
} else {
c.x = x
c.y = y
}
}
func (c *BaseControl) applyConstraints() {
@@ -390,6 +423,10 @@ func (c *BaseControl) AddChild(control Control) {
mainCtrl.ResizeChildren()
mainCtrl.PlaceChildren()
}
if c.clipped && c.clipper == nil {
c.setClipper()
}
}
func (c *BaseControl) Children() []Control {
@@ -443,6 +480,10 @@ func (c *BaseControl) MinimalSize() (w int, h int) {
}
for _, ctrl := range c.children {
if ctrl.Clipped() {
continue
}
if !ctrl.Visible() {
continue
}
@@ -482,13 +523,37 @@ func (c *BaseControl) DrawChildren() {
PushClip()
defer PopClip()
SetClipRect(c.x+c.padX, c.y+c.padY, c.width-2*c.padX, c.height-2*c.padY)
cp := ClippedParent(c)
var cTarget Control
cTarget = c
if cp != nil {
cTarget = cp
}
x, y, w, h := cTarget.Clipper()
SetClipRect(x, y, w, h)
for _, child := range c.children {
child.Draw()
}
}
func (c *BaseControl) Clipper() (int, int, int, int) {
clipped := ClippedParent(c)
if clipped == nil || (c.clipped && c.clipper != nil) {
return c.clipper.x, c.clipper.y, c.clipper.w, c.clipper.h
}
return CalcClipper(clipped)
}
func (c *BaseControl) setClipper() {
x, y, w, h := CalcClipper(c)
c.clipper = &rect{x: x, y: y, w: w, h: h}
}
func (c *BaseControl) HitTest(x, y int) HitResult {
if x > c.x && x < c.x+c.width-1 &&
y > c.y && y < c.y+c.height-1 {
@@ -572,4 +637,5 @@ func (c *BaseControl) removeChild(control Control) {
// Destroy removes an object from its parental chain
func (c *BaseControl) Destroy() {
c.parent.removeChild(c)
c.parent.SetConstraints(0, 0)
}
+4 -4
View File
@@ -77,13 +77,13 @@ func (b *Button) Draw() {
w, h := b.Size()
fg, bg := b.fg, b.bg
shadow := RealColor(b.shadowColor, ColorButtonShadow)
shadow := RealColor(b.shadowColor, b.Style(), ColorButtonShadow)
if b.disabled {
fg, bg = RealColor(fg, ColorButtonDisabledText), RealColor(bg, ColorButtonDisabledBack)
fg, bg = RealColor(fg, b.Style(), ColorButtonDisabledText), RealColor(bg, b.Style(), ColorButtonDisabledBack)
} else if b.Active() {
fg, bg = RealColor(b.fgActive, ColorButtonActiveText), RealColor(b.bgActive, ColorButtonActiveBack)
fg, bg = RealColor(b.fgActive, b.Style(), ColorButtonActiveText), RealColor(b.bgActive, b.Style(), ColorButtonActiveBack)
} else {
fg, bg = RealColor(fg, ColorButtonText), RealColor(bg, ColorButtonBack)
fg, bg = RealColor(fg, b.Style(), ColorButtonText), RealColor(bg, b.Style(), ColorButtonBack)
}
dy := int((h - 1) / 2)
+4 -4
View File
@@ -276,12 +276,12 @@ func DrawText(x, y int, text string) {
SetBackColor(elem.Bg)
drawn := PutChar(x, y, elem.Ch)
if unicode.Is(unicode.Scripts["Han"], elem.Ch){
if unicode.Is(unicode.Scripts["Han"], elem.Ch) {
x += 2
} else {
x += 1
}
if firstdrawn && !drawn {
break
}
@@ -432,9 +432,9 @@ func DrawScrollBar(x, y, w, h, pos int) {
PushAttributes()
defer PopAttributes()
fg, bg := RealColor(ColorDefault, ColorScrollText), RealColor(ColorDefault, ColorScrollBack)
fg, bg := RealColor(ColorDefault, "", ColorScrollText), RealColor(ColorDefault, "", ColorScrollBack)
// TODO: add thumb styling
// fgThumb, bgThumb := RealColor(ColorDefault, ColorThumbText), RealColor(ColorDefault, ColorThumbBack)
// fgThumb, bgThumb := RealColor(ColorDefault, "", ColorThumbText), RealColor(ColorDefault, "", ColorThumbBack)
SetTextColor(fg)
SetBackColor(bg)
+5
View File
@@ -1,3 +1,8 @@
2018-09-06 - version 0.9.0 RC3 (Thanks to Leandro Dorileo)
[+] New big feature: scrollable Frame
[+] Custom theme support: overriding theme colors with custom ones
[*] Fix bug in getLinearControlList
2018-08-13 - version 0.9.0 RC2
[+] New control: LoginDialog (a dialog with username and password fields)
+3 -3
View File
@@ -66,11 +66,11 @@ func (c *CheckBox) Draw() {
x, y := c.Pos()
w, h := c.Size()
fg, bg := RealColor(c.fg, ColorControlText), RealColor(c.bg, ColorControlBack)
fg, bg := RealColor(c.fg, c.Style(), ColorControlText), RealColor(c.bg, c.Style(), ColorControlBack)
if !c.Enabled() {
fg, bg = RealColor(c.fg, ColorControlDisabledText), RealColor(c.bg, ColorControlDisabledBack)
fg, bg = RealColor(c.fg, c.Style(), ColorControlDisabledText), RealColor(c.bg, c.Style(), ColorControlDisabledBack)
} else if c.Active() {
fg, bg = RealColor(c.fg, ColorControlActiveText), RealColor(c.bg, ColorControlActiveBack)
fg, bg = RealColor(c.fg, c.Style(), ColorControlActiveText), RealColor(c.bg, c.Style(), ColorControlActiveBack)
}
parts := []rune(SysObject(ObjCheckBox))
+3
View File
@@ -291,6 +291,9 @@ const (
EventCloseWindow
// Make a control (Target field of Event structure) to recalculate and reposition all its children
EventLayout
// A scroll-able control's child has been activated, then notify its parent to handle
// the scrolling
EventActivateChild
)
// ConfirmationDialog and SelectDialog exit codes
+16
View File
@@ -157,4 +157,20 @@ type Control interface {
// it implies this control will stop receiving events and will not be drawn nor
// will impact on other objects position and size calculation
Destroy()
// SetStyle sets a control's custom style grouper/modifier, with a style set
// the control will prefix the control theme with style, i.e if a button is modified
// and set style to "MyCustom" then the theme will engine will first attempt to apply
// MyCustomButtonBack and MyCustomButtonText if not present then apply the default
// and standard ButtonBack and ButtonText
SetStyle(style string)
// Style returns the custom style grouper/modifier
Style() string
// SetClipped marks a control as clip-able, meaning the children components will not
// affect the control's size - i.e will not make it expand
SetClipped(clipped bool)
// Clipped returns the current control's clipped flag
Clipped() bool
// Clipper if the component is clipped then return the clipper geometry, however
// the size and pos is returned
Clipper() (int, int, int, int)
}
+52 -2
View File
@@ -192,7 +192,7 @@ func getLinearControlList(parent Control, fn func(Control) bool) []Control {
result := []Control{}
for _, curr := range parent.Children() {
if fn(curr) {
if fn != nil && fn(curr) {
result = append(result, curr)
}
@@ -266,8 +266,58 @@ func SendEventToChild(parent Control, ev Event) bool {
}
if child != nil && child != parent {
return child.ProcessEvent(ev)
ev.Target = child
res := child.ProcessEvent(ev)
if cparent := ClippedParent(child); cparent != nil && cparent != child {
cparent.ProcessEvent(ev)
}
return res
}
return false
}
// CalcClipper calculates the clipper size based on the control's size, position
// and paddings
func CalcClipper(c Control) (int, int, int, int) {
w, h := c.Size()
x, y := c.Pos()
px, py := c.Paddings()
x = x + px
y = y + py
w = w - 2*px
h = h - 2*py
return x, y, w, h
}
// ClippedParent finds the first c parent with clipped flag
func ClippedParent(c Control) Control {
var clipped Control
ctrl := c.Parent()
clipped = c
for ctrl != nil {
if ctrl.Clipped() {
clipped = ctrl
break
}
ctrl = ctrl.Parent()
}
return clipped
}
// ControlInRect returns true if c is within a given rect
func ControlInRect(c Control, x int, y int, w int, h int) bool {
xx, yy := c.Pos()
ww, hh := c.Size()
return xx >= x && ww <= x+w && yy <= y+h &&
yy+hh <= y+h && yy >= y && yy+h >= y
}
+3 -3
View File
@@ -99,11 +99,11 @@ func (e *EditField) Draw() {
}
}
fg, bg := RealColor(e.fg, ColorEditText), RealColor(e.bg, ColorEditBack)
fg, bg := RealColor(e.fg, e.Style(), ColorEditText), RealColor(e.bg, e.Style(), ColorEditBack)
if !e.Enabled() {
fg, bg = RealColor(e.fg, ColorDisabledText), RealColor(e.fg, ColorDisabledBack)
fg, bg = RealColor(e.fg, e.Style(), ColorDisabledText), RealColor(e.fg, e.Style(), ColorDisabledBack)
} else if e.Active() {
fg, bg = RealColor(e.fg, ColorEditActiveText), RealColor(e.bg, ColorEditActiveBack)
fg, bg = RealColor(e.fg, e.Style(), ColorEditActiveText), RealColor(e.bg, e.Style(), ColorEditActiveBack)
}
SetTextColor(fg)
+116 -8
View File
@@ -2,6 +2,7 @@ package clui
import (
xs "github.com/huandu/xstrings"
"math"
)
/*
@@ -12,9 +13,11 @@ is required
*/
type Frame struct {
BaseControl
border BorderStyle
children []Control
pack PackType
border BorderStyle
children []Control
pack PackType
scrollable bool
lastScrollProp int
}
/*
@@ -58,6 +61,30 @@ func CreateFrame(parent Control, width, height int, bs BorderStyle, scale int) *
return f
}
func (f *Frame) SetScrollable(scrollable bool) {
f.scrollable = scrollable
if scrollable {
px, py := f.Paddings()
if f.Pack() == Vertical {
px += 1
}
if f.Pack() == Horizontal {
py += 1
}
f.SetPaddings(px, py)
}
f.SetClipped(scrollable)
}
func (f *Frame) Scrollable() bool {
return f.scrollable
}
// Repaint draws the control on its View surface
func (f *Frame) Draw() {
if f.hidden {
@@ -67,16 +94,52 @@ func (f *Frame) Draw() {
PushAttributes()
defer PopAttributes()
x, y, w, h := f.Clipper()
if f.scrollable {
_, fy := f.Pos()
_, fh := f.Size()
_, fpy := f.Paddings()
var dist float64
prop := 0
ctrl := ActiveControl(f)
if ctrl != nil {
var frameProp float64
_, ty := ctrl.Pos()
dist = (float64(fy) + float64(fpy)) - float64(ty)
dist = math.Sqrt(dist * dist)
if dist > 0 {
frameProp = (dist * 100) / float64(fh)
}
if frameProp > 0 {
prop = int(math.Round((float64(h-2) / (100 / frameProp))))
}
f.lastScrollProp = prop
}
DrawScrollBar(x+w, y, 1, h, f.lastScrollProp)
}
fg, bg := RealColor(f.fg, f.Style(), ColorViewText), RealColor(f.bg, f.Style(), ColorViewBack)
if f.border == BorderNone {
if bg != ColorDefault {
SetBackColor(bg)
FillRect(x, y, w, h, ' ')
}
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)
@@ -92,3 +155,48 @@ func (f *Frame) Draw() {
f.DrawChildren()
}
func (f *Frame) ProcessEvent(ev Event) bool {
if ev.Type != EventActivateChild || (!f.scrollable || ev.Target == nil) {
return false
}
x, y := f.Pos()
px, py := f.Paddings()
cx, cy, cw, ch := f.Clipper()
tw, th := ev.Target.Size()
tx, ty := ev.Target.Pos()
if ControlInRect(ev.Target, cx, cy, cw, ch) {
return false
}
xx := x
yy := y
if (ty+th)-(py/2) > cy+ch {
delta := (ty + th) - (cy + ch)
yy = y - delta
} else if ty < cy {
delta := cy - ty
yy = y + delta
}
if (tx+tw)-(px/2) > cx+cw {
delta := (tx + tw) - (cx + cw)
xx = (x - delta)
} else if tx < cx {
delta := cx - tx
xx = x + delta
}
f.x = xx
f.y = yy
f.ResizeChildren()
f.PlaceChildren()
return false
}
+2 -2
View File
@@ -73,9 +73,9 @@ func (l *Label) Draw() {
PushAttributes()
defer PopAttributes()
fg, bg := RealColor(l.fg, ColorText), RealColor(l.bg, ColorBack)
fg, bg := RealColor(l.fg, l.Style(), ColorText), RealColor(l.bg, l.Style(), ColorBack)
if !l.Enabled() {
fg = RealColor(l.fg, ColorDisabledText)
fg = RealColor(l.fg, l.Style(), ColorDisabledText)
}
SetTextColor(fg)
+5 -5
View File
@@ -87,11 +87,11 @@ func (l *ListBox) drawItems() {
maxDy := l.height - 1
maxWidth := l.width - 1
fg, bg := RealColor(l.fg, ColorEditText), RealColor(l.bg, ColorEditBack)
fg, bg := RealColor(l.fg, l.Style(), ColorEditText), RealColor(l.bg, l.Style(), ColorEditBack)
if l.Active() {
fg, bg = RealColor(l.fg, ColorEditActiveText), RealColor(l.bg, ColorEditActiveBack)
fg, bg = RealColor(l.fg, l.Style(), ColorEditActiveText), RealColor(l.bg, l.Style(), ColorEditActiveBack)
}
fgSel, bgSel := RealColor(l.fgActive, ColorSelectionText), RealColor(l.bgActive, ColorSelectionBack)
fgSel, bgSel := RealColor(l.fgActive, l.Style(), ColorSelectionText), RealColor(l.bgActive, l.Style(), ColorSelectionBack)
for curr <= maxCurr && dy <= maxDy {
f, b := fg, bg
@@ -122,9 +122,9 @@ func (l *ListBox) Draw() {
x, y := l.Pos()
w, h := l.Size()
fg, bg := RealColor(l.fg, ColorEditText), RealColor(l.bg, ColorEditBack)
fg, bg := RealColor(l.fg, l.Style(), ColorEditText), RealColor(l.bg, l.Style(), ColorEditBack)
if l.Active() {
fg, bg = RealColor(l.fg, ColorEditActiveText), RealColor(l.bg, ColorEditActiveBack)
fg, bg = RealColor(l.fg, l.Style(), ColorEditActiveText), RealColor(l.bg, l.Style(), ColorEditActiveBack)
}
SetTextColor(fg)
SetBackColor(bg)
+3 -3
View File
@@ -85,8 +85,8 @@ func (b *ProgressBar) Draw() {
PushAttributes()
defer PopAttributes()
fgOff, fgOn := RealColor(b.fg, ColorProgressText), RealColor(b.fgActive, ColorProgressActiveText)
bgOff, bgOn := RealColor(b.bg, ColorProgressBack), RealColor(b.bgActive, ColorProgressActiveBack)
fgOff, fgOn := RealColor(b.fg, b.Style(), ColorProgressText), RealColor(b.fgActive, b.Style(), ColorProgressActiveText)
bgOff, bgOn := RealColor(b.bg, b.Style(), ColorProgressBack), RealColor(b.bgActive, b.Style(), ColorProgressActiveBack)
parts := []rune(SysObject(ObjProgressBar))
cFilled, cEmpty := parts[0], parts[1]
@@ -126,7 +126,7 @@ func (b *ProgressBar) Draw() {
if title != "" {
shift, str := AlignText(title, w, b.align)
titleClr := RealColor(b.titleFg, ColorProgressTitleText)
titleClr := RealColor(b.titleFg, b.Style(), ColorProgressTitleText)
var sOn, sOff string
if filled == 0 || shift >= filled {
sOff = str
+3 -3
View File
@@ -59,11 +59,11 @@ func (c *Radio) Draw() {
x, y := c.Pos()
w, h := c.Size()
fg, bg := RealColor(c.fg, ColorControlText), RealColor(c.bg, ColorControlBack)
fg, bg := RealColor(c.fg, c.Style(), ColorControlText), RealColor(c.bg, c.Style(), ColorControlBack)
if !c.Enabled() {
fg, bg = RealColor(c.fg, ColorControlDisabledText), RealColor(c.bg, ColorControlDisabledBack)
fg, bg = RealColor(c.fg, c.Style(), ColorControlDisabledText), RealColor(c.bg, c.Style(), ColorControlDisabledBack)
} else if c.Active() {
fg, bg = RealColor(c.fg, ColorControlActiveText), RealColor(c.bg, ColorControlActiveBack)
fg, bg = RealColor(c.fg, c.Style(), ColorControlActiveText), RealColor(c.bg, c.Style(), ColorControlActiveBack)
}
parts := []rune(SysObject(ObjRadio))
+3 -3
View File
@@ -83,7 +83,7 @@ func (b *SparkChart) Draw() {
PushAttributes()
defer PopAttributes()
fg, bg := RealColor(b.fg, ColorSparkChartText), RealColor(b.bg, ColorSparkChartBack)
fg, bg := RealColor(b.fg, b.Style(), ColorSparkChartText), RealColor(b.bg, b.Style(), ColorSparkChartBack)
SetTextColor(fg)
SetBackColor(bg)
FillRect(b.x, b.y, b.width, b.height, ' ')
@@ -117,8 +117,8 @@ func (b *SparkChart) drawBars() {
h := b.height
pos := b.x + start
mxFg, mxBg := RealColor(b.maxFg, ColorSparkChartMaxText), RealColor(b.maxBg, ColorSparkChartMaxBack)
brFg, brBg := RealColor(b.fg, ColorSparkChartBarText), RealColor(b.bg, ColorSparkChartBarBack)
mxFg, mxBg := RealColor(b.maxFg, b.Style(), ColorSparkChartMaxText), RealColor(b.maxBg, b.Style(), ColorSparkChartMaxBack)
brFg, brBg := RealColor(b.fg, b.Style(), ColorSparkChartBarText), RealColor(b.bg, b.Style(), ColorSparkChartBarBack)
parts := []rune(SysObject(ObjSparkChart))
var dt []float64
+7 -7
View File
@@ -164,8 +164,8 @@ func (l *TableView) drawHeader() {
PushAttributes()
defer PopAttributes()
fg, bg := RealColor(l.fg, ColorTableHeaderText), RealColor(l.bg, ColorTableHeaderBack)
fgLine := RealColor(l.fg, ColorTableLineText)
fg, bg := RealColor(l.fg, l.Style(), ColorTableHeaderText), RealColor(l.bg, l.Style(), ColorTableHeaderBack)
fgLine := RealColor(l.fg, l.Style(), ColorTableLineText)
x, y := l.Pos()
w, _ := l.Size()
SetTextColor(fg)
@@ -269,10 +269,10 @@ func (l *TableView) drawCells() {
dy := 2
maxDy := l.height - 2
fg, bg := RealColor(l.fg, ColorTableText), RealColor(l.bg, ColorTableBack)
fgRow, bgRow := RealColor(l.fg, ColorTableSelectedText), RealColor(l.bg, ColorTableSelectedBack)
fgCell, bgCell := RealColor(l.fg, ColorTableActiveCellText), RealColor(l.bg, ColorTableActiveCellBack)
fgLine := RealColor(l.fg, ColorTableLineText)
fg, bg := RealColor(l.fg, l.Style(), ColorTableText), RealColor(l.bg, l.Style(), ColorTableBack)
fgRow, bgRow := RealColor(l.fg, l.Style(), ColorTableSelectedText), RealColor(l.bg, l.Style(), ColorTableSelectedBack)
fgCell, bgCell := RealColor(l.fg, l.Style(), ColorTableActiveCellText), RealColor(l.bg, l.Style(), ColorTableActiveCellBack)
fgLine := RealColor(l.fg, l.Style(), ColorTableLineText)
parts := []rune(SysObject(ObjTableView))
start := 0
@@ -361,7 +361,7 @@ func (l *TableView) Draw() {
x, y := l.Pos()
w, h := l.Size()
bg := RealColor(l.bg, ColorTableBack)
bg := RealColor(l.bg, l.Style(), ColorTableBack)
SetBackColor(bg)
FillRect(x, y+2, w, h-2, ' ')
l.drawHeader()
+4 -4
View File
@@ -50,9 +50,9 @@ func (l *TextReader) drawText() {
PushAttributes()
defer PopAttributes()
bg, fg := RealColor(l.bg, ColorEditBack), RealColor(l.fg, ColorEditText)
bg, fg := RealColor(l.bg, l.Style(), ColorEditBack), RealColor(l.fg, l.Style(), ColorEditText)
if l.Active() {
bg, fg = RealColor(l.bg, ColorEditActiveBack), RealColor(l.fg, ColorEditActiveText)
bg, fg = RealColor(l.bg, l.Style(), ColorEditActiveBack), RealColor(l.fg, l.Style(), ColorEditActiveText)
}
SetTextColor(fg)
SetBackColor(bg)
@@ -91,9 +91,9 @@ func (l *TextReader) Draw() {
x, y := l.Pos()
w, h := l.Size()
bg, fg := RealColor(l.bg, ColorEditBack), RealColor(l.fg, ColorEditText)
bg, fg := RealColor(l.bg, l.Style(), ColorEditBack), RealColor(l.fg, l.Style(), ColorEditText)
if l.Active() {
bg, fg = RealColor(l.bg, ColorEditActiveBack), RealColor(l.fg, ColorEditActiveText)
bg, fg = RealColor(l.bg, l.Style(), ColorEditActiveBack), RealColor(l.fg, l.Style(), ColorEditActiveText)
}
SetTextColor(fg)
+2 -2
View File
@@ -177,9 +177,9 @@ func (l *TextView) Draw() {
x, y := l.Pos()
w, h := l.Size()
bg, fg := RealColor(l.bg, ColorEditBack), RealColor(l.fg, ColorEditText)
bg, fg := RealColor(l.bg, l.Style(), ColorEditBack), RealColor(l.fg, l.Style(), ColorEditText)
if l.Active() {
bg, fg = RealColor(l.bg, ColorEditActiveBack), RealColor(l.fg, ColorEditActiveText)
bg, fg = RealColor(l.bg, l.Style(), ColorEditActiveBack), RealColor(l.fg, l.Style(), ColorEditActiveText)
}
SetTextColor(fg)
+24 -3
View File
@@ -508,15 +508,36 @@ func ThemeInfo(name string) ThemeDesc {
// Attribute selection work this way: if color is not ColorDefault,
// it is returned as is, otherwise the function tries to load
// color from the theme.
//
// With the style argument themes may be grouped by control, i.e
// an application may have multiple list controls where they all share
// the same theme attributes however the same application may have
// one specific list control with some different theme attributes,
// in that case the user may call control.SetStyle("custom") and define
// a set of custom.* attributes, i.e:
//
// custom.EditBox = white
// custom.EditText = black bold
// ...
//
// clr - current object color
// style - the theme prefix style set
// id - color ID in theme
func RealColor(clr term.Attribute, id string) term.Attribute {
func RealColor(clr term.Attribute, style string, id string) term.Attribute {
var prefix string
if style != "" {
prefix = fmt.Sprintf("%s.", style)
}
ccolor := fmt.Sprintf("%s%s", prefix, id)
if clr == ColorDefault {
clr = SysColor(id)
clr = SysColor(ccolor)
}
if clr == ColorDefault {
panic("Failed to load color value for " + id)
panic("Failed to load color value for " + ccolor)
}
return clr
+33 -5
View File
@@ -21,8 +21,14 @@ type Window struct {
fixedSize bool
onClose func(Event) bool
onKeyDown func(Event) bool
onScreenResize func(Event)
onKeyDown *keyDownCb
}
type keyDownCb struct {
data interface{}
fn func(evt Event, data interface{}) bool
}
func CreateWindow(x, y, w, h int, title string) *Window {
@@ -133,7 +139,7 @@ func (wnd *Window) Draw() {
PushAttributes()
defer PopAttributes()
fg, bg := RealColor(wnd.fg, ColorViewText), RealColor(wnd.bg, ColorViewBack)
fg, bg := RealColor(wnd.fg, wnd.Style(), ColorViewText), RealColor(wnd.bg, wnd.Style(), ColorViewBack)
SetBackColor(bg)
FillRect(wnd.x, wnd.y, wnd.width, wnd.height, ' ')
@@ -233,6 +239,24 @@ func (c *Window) ProcessEvent(ev Event) bool {
aC := ActiveControl(c)
nC := NextControl(c, aC, ev.Key != term.KeyArrowUp)
var clipped Control
if aC != nil && aC.Clipped() {
clipped = aC
} else {
clipped = ClippedParent(nC)
}
if clipped != nil {
dir := 1
if ev.Key != term.KeyArrowUp {
dir = -1
}
clipped.ProcessEvent(Event{Type: EventActivateChild, Target: nC, X: dir})
}
if nC != aC {
if aC != nil {
aC.SetActive(false)
@@ -249,7 +273,7 @@ func (c *Window) ProcessEvent(ev Event) bool {
return true
}
if c.onKeyDown != nil {
return c.onKeyDown(ev)
return c.onKeyDown.fn(ev, c.onKeyDown.data)
}
return false
}
@@ -270,8 +294,12 @@ func (w *Window) OnClose(fn func(Event) bool) {
// OnKeyDown sets the callback that is called when a user presses a key
// while the Window is active
func (w *Window) OnKeyDown(fn func(Event) bool) {
w.onKeyDown = fn
func (w *Window) OnKeyDown(fn func(Event, interface{}) bool, data interface{}) {
if fn == nil {
w.onKeyDown = nil
} else {
w.onKeyDown = &keyDownCb{data: data, fn: fn}
}
}
// OnScreenResize sets the callback that is called when size of terminal changes
+1
View File
@@ -55,6 +55,7 @@ Here is a list of functions in [strings](http://golang.org/pkg/strings) and [xst
| [Successor](https://godoc.org/github.com/huandu/xstrings#Successor) | `String#succ` or `String#next` in Ruby | [#22](https://github.com/huandu/xstrings/issues/22) |
| [SwapCase](https://godoc.org/github.com/huandu/xstrings#SwapCase) | `str.swapcase` in Python; `String#swapcase` in Ruby | [#12](https://github.com/huandu/xstrings/issues/12) |
| [ToCamelCase](https://godoc.org/github.com/huandu/xstrings#ToCamelCase) | `String#camelize` in RoR | [#1](https://github.com/huandu/xstrings/issues/1) |
| [ToKebab](https://godoc.org/github.com/huandu/xstrings#ToKebabCase) | - | [#41](https://github.com/huandu/xstrings/issues/41) |
| [ToSnakeCase](https://godoc.org/github.com/huandu/xstrings#ToSnakeCase) | `String#underscore` in RoR | [#1](https://github.com/huandu/xstrings/issues/1) |
| [Translate](https://godoc.org/github.com/huandu/xstrings#Translate) | `str.translate` in Python; `String#tr` in Ruby; `strtr` in PHP; `tr///` in Perl | [#21](https://github.com/huandu/xstrings/issues/21) |
| [Width](https://godoc.org/github.com/huandu/xstrings#Width) | `mb_strwidth` in PHP | [#26](https://github.com/huandu/xstrings/issues/26) |
+36 -15
View File
@@ -72,7 +72,7 @@ func ToCamelCase(str string) string {
}
// ToSnakeCase can convert all upper case characters in a string to
// underscore format.
// snake case format.
//
// Some samples.
// "FirstName" => "first_name"
@@ -85,6 +85,27 @@ func ToCamelCase(str string) string {
// "http2xx" => "http_2xx"
// "HTTP20xOK" => "http_20x_ok"
func ToSnakeCase(str string) string {
return camelCaseToLowerCase(str, '_')
}
// ToKebabCase can convert all upper case characters in a string to
// kebab case format.
//
// Some samples.
// "FirstName" => "first-name"
// "HTTPServer" => "http-server"
// "NoHTTPS" => "no-https"
// "GO_PATH" => "go-path"
// "GO PATH" => "go-path" // space is converted to '-'.
// "GO-PATH" => "go-path" // hyphen is converted to '-'.
// "HTTP2XX" => "http-2xx" // insert a '-' before a number and after an alphabet.
// "http2xx" => "http-2xx"
// "HTTP20xOK" => "http-20x-ok"
func ToKebabCase(str string) string {
return camelCaseToLowerCase(str, '-')
}
func camelCaseToLowerCase(str string, connector rune) string {
if len(str) == 0 {
return ""
}
@@ -93,7 +114,7 @@ func ToSnakeCase(str string) string {
var prev, r0, r1 rune
var size int
r0 = '_'
r0 = connector
for len(str) > 0 {
prev = r0
@@ -102,11 +123,11 @@ func ToSnakeCase(str string) string {
switch {
case r0 == utf8.RuneError:
buf.WriteByte(byte(str[0]))
buf.WriteRune(r0)
case unicode.IsUpper(r0):
if prev != '_' && !unicode.IsNumber(prev) {
buf.WriteRune('_')
if prev != connector && !unicode.IsNumber(prev) {
buf.WriteRune(connector)
}
buf.WriteRune(unicode.ToLower(r0))
@@ -123,7 +144,7 @@ func ToSnakeCase(str string) string {
break
}
// find next non-upper-case character and insert `_` properly.
// find next non-upper-case character and insert connector properly.
// it's designed to convert `HTTPServer` to `http_server`.
// if there are more than 2 adjacent upper case characters in a word,
// treat them as an abbreviation plus a normal word.
@@ -134,23 +155,23 @@ func ToSnakeCase(str string) string {
if r0 == utf8.RuneError {
buf.WriteRune(unicode.ToLower(r1))
buf.WriteByte(byte(str[0]))
buf.WriteRune(r0)
break
}
if !unicode.IsUpper(r0) {
if r0 == '_' || r0 == ' ' || r0 == '-' {
r0 = '_'
r0 = connector
buf.WriteRune(unicode.ToLower(r1))
} else if unicode.IsNumber(r0) {
// treat a number as an upper case rune
// so that both `http2xx` and `HTTP2XX` can be converted to `http_2xx`.
buf.WriteRune(unicode.ToLower(r1))
buf.WriteRune('_')
buf.WriteRune(connector)
buf.WriteRune(r0)
} else {
buf.WriteRune('_')
buf.WriteRune(connector)
buf.WriteRune(unicode.ToLower(r1))
buf.WriteRune(r0)
}
@@ -161,20 +182,20 @@ func ToSnakeCase(str string) string {
buf.WriteRune(unicode.ToLower(r1))
}
if len(str) == 0 || r0 == '_' {
if len(str) == 0 || r0 == connector {
buf.WriteRune(unicode.ToLower(r0))
}
case unicode.IsNumber(r0):
if prev != '_' && !unicode.IsNumber(prev) {
buf.WriteRune('_')
if prev != connector && !unicode.IsNumber(prev) {
buf.WriteRune(connector)
}
buf.WriteRune(r0)
default:
if r0 == ' ' || r0 == '-' {
r0 = '_'
if r0 == ' ' || r0 == '-' || r0 == '_' {
r0 = connector
}
buf.WriteRune(r0)