From fc065fd89a90c2d070dcd02be1d2ae6f7059d6c7 Mon Sep 17 00:00:00 2001 From: raziman Date: Thu, 18 Jun 2020 14:30:20 +0800 Subject: [PATCH] first commit --- .gitignore | 15 +++ go.mod | 5 + go.sum | 22 ++++ gomu.go | 316 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 358 insertions(+) create mode 100644 .gitignore create mode 100644 go.mod create mode 100644 go.sum create mode 100644 gomu.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..66fd13c --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d1ece37 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/issadarkthing/gomu + +go 1.14 + +require github.com/rivo/tview v0.0.0-20200528200248-fe953220389f // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..4031aaa --- /dev/null +++ b/go.sum @@ -0,0 +1,22 @@ +github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= +github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= +github.com/gdamore/tcell v1.3.0 h1:r35w0JBADPZCVQijYebl6YMWWtHRqVEGt7kL2eBADRM= +github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= +github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= +github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= +github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0= +github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/rivo/tview v0.0.0-20200528200248-fe953220389f h1:tRx/LLIP2PSA7johw9xhf+6NUCLC4BbMhpGdm110MGI= +github.com/rivo/tview v0.0.0-20200528200248-fe953220389f/go.mod h1:6lkG1x+13OShEf0EaOCaTQYyB7d5nSbb181KtjlS+84= +github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 h1:sfkvUWPNGwSV+8/fNqctR5lS2AqCSqYwXdrjCxp/dXo= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/gomu.go b/gomu.go new file mode 100644 index 0000000..4945f5a --- /dev/null +++ b/gomu.go @@ -0,0 +1,316 @@ +package main + +import ( + "os" + + "github.com/gdamore/tcell" + "github.com/rivo/tview" +) + +func main() { + + app := tview.NewApplication() + + start(app) + +} + + +func start(app *tview.Application) { + // override default border + // change double line border to one line border when focused + tview.Borders.HorizontalFocus = tview.Borders.Horizontal + tview.Borders.VerticalFocus = tview.Borders.Vertical + tview.Borders.TopLeftFocus = tview.Borders.TopLeft + tview.Borders.TopRightFocus = tview.Borders.TopRight + tview.Borders.BottomLeftFocus = tview.Borders.BottomLeft + tview.Borders.BottomRightFocus = tview.Borders.BottomRight + tview.Styles.PrimitiveBackgroundColor = tcell.ColorDefault + tview.Styles.BorderColor = tcell.ColorAntiqueWhite + + child1, child2, child3 := playlist(), queue(), nowPlayingBar() + + flex := layout(app, child1, child2, child3) + + childrens := []Children{child1, child2, child3} + + app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { + + switch event.Key() { + // cycle through each section + case tcell.KeyTAB: + cycleChildren(app, childrens) + + } + + switch event.Rune() { + case 'q': + confirmationPopup(app, flex, "Are you sure to exit?") + } + + return event + }) + + + // fix transparent background issue + app.SetBeforeDrawFunc(func(screen tcell.Screen) bool { + screen.Clear() + return false + }) + + // main loop + if err := app.SetRoot(flex, true).SetFocus(flex).Run(); err != nil { + panic(err) + } +} + + +func cycleChildren(app *tview.Application, childrens []Children) { + + focusedColor := tcell.ColorDarkCyan + unfocusedColor := tcell.ColorAntiqueWhite + anyChildHasFocus := false + + for i, child := range childrens { + + if child.HasFocus() { + + anyChildHasFocus = true + + var nextChild Children + + // if its the last element set the child back to one + if i == len(childrens) - 1 { + nextChild = childrens[0] + } else { + nextChild = childrens[i + 1] + } + + + child.SetBorderColor(unfocusedColor) + child.SetTitleColor(unfocusedColor) + + app.SetFocus(nextChild.(tview.Primitive)) + nextChild.SetBorderColor(focusedColor) + nextChild.SetTitleColor(focusedColor) + + break + } + } + + if anyChildHasFocus == false { + + app.SetFocus(childrens[0].(tview.Primitive)) + childrens[0].SetBorderColor(focusedColor) + childrens[0].SetTitleColor(focusedColor) + } + +} + +// created so we can keep track of childrens in slices +type Children interface { + HasFocus() bool + SetBorderColor(color tcell.Color) *tview.Box + SetTitleColor(color tcell.Color) *tview.Box + SetTitle(s string) *tview.Box + GetTitle() string +} + + +func layout( + app *tview.Application, + child1 *tview.TreeView, + child2 *tview.List, + child3 *tview.Box, +) *tview.Flex { + + flex := tview.NewFlex(). + AddItem(child1, 0, 1, false). + AddItem(tview.NewFlex().SetDirection(tview.FlexRow). + AddItem(child2, 0, 7, false). + AddItem(child3, 0, 1, false), 0, 3, false) + + return flex + +} + +func nowPlayingBar() *tview.Box { + return tview.NewBox().SetBorder(true). + SetTitle("Currently Playing") +} + +func queue() *tview.List { + + list := tview.NewList(). + AddItem("Lorem", "ipsum", '1', nil). + AddItem("Lorem", "ipsum", '2', nil). + AddItem("Lorem", "ipsum", '3', nil). + AddItem("Lorem", "ipsum", '4', nil). + AddItem("Lorem", "ipsum", '5', nil). + ShowSecondaryText(false) + + list.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey { + + switch e.Rune() { + case 'j': + next(list) + case 'k': + prev(list) + } + + return nil + }) + + list.SetHighlightFullLine(true) + list.SetBorder(true).SetTitle("Queue") + list.SetSelectedBackgroundColor(tcell.ColorDarkCyan) + list.SetSelectedTextColor(tcell.ColorAntiqueWhite) + + return list + +} + +func confirmationPopup(app *tview.Application, flex *tview.Flex, text string) bool { + + result := false + + modal := tview.NewModal(). + SetText(text). + SetBackgroundColor(tcell.ColorDefault). + AddButtons([]string{"yes", "no"}). + SetButtonBackgroundColor(tcell.ColorBlack). + SetDoneFunc(func(_ int, buttonLabel string) { + if buttonLabel == "yes" { + result = true + app.Stop() + } + + app.SetRoot(flex, true) + }); + + + app.SetRoot(modal, false).SetFocus(modal) + + return result + +} + +func next(l *tview.List) { + currIndex := l.GetCurrentItem() + idx := currIndex + 1 + if currIndex == l.GetItemCount() - 1 { + idx = 0 + } + l.SetCurrentItem(idx) +} + +func prev(l *tview.List) { + currIndex := l.GetCurrentItem() + l.SetCurrentItem(currIndex - 1) +} + +func playlist() *tview.TreeView { + + rootDir := "~/Music" + root := tview.NewTreeNode(rootDir) + tree := tview.NewTreeView().SetRoot(root) + tree.SetTitle("Playlist").SetBorder(true) + tree.SetGraphicsColor(tcell.ColorWhite) + + textColor := tcell.ColorAntiqueWhite + backGroundColor := tcell.ColorDarkCyan + + sample := [][]string{ + {"pop", "1", "2", "3"}, + {"rock", "1", "2", "3"}, + {"rap", "1", "2", "3"}, + {"country", "1", "2", "3"}, + {"edm", "1", "2", "3"}, + } + + var childrens []*tview.TreeNode + + // populate tree with sample + for _, s := range sample { + + node := tview.NewTreeNode(s[0]) + + node.SetExpanded(false) + + for _, sy := range s[1:] { + + child := tview.NewTreeNode(sy) + child.SetIndent(5) + child.SetReference(node) + node.AddChild(child) + + } + childrens = append(childrens, node) + root.AddChild(node) + } + + childrens[0].SetColor(backGroundColor) + + tree.SetCurrentNode(childrens[0]) + // keep track of prev node so we can remove the color of highlight + prevNode := childrens[0].SetColor(backGroundColor) + + tree.SetChangedFunc(func (node *tview.TreeNode) { + + prevNode.SetColor(textColor) + root.SetColor(textColor) + node.SetColor(backGroundColor) + prevNode = node + }) + + tree.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey { + + currNode := tree.GetCurrentNode() + + switch e.Rune() { + case 'l': + currNode.SetExpanded(true) + case 'h': + + // if closing node with no children + // close the node's parent + if parent := currNode.GetReference(); parent != nil { + // remove the color of the node + currNode.SetColor(textColor) + parent.(*tview.TreeNode).SetExpanded(false) + parent.(*tview.TreeNode).SetColor(backGroundColor) + prevNode = parent.(*tview.TreeNode) + tree.SetCurrentNode(parent.(*tview.TreeNode)) + } else { + currNode.SetExpanded(false) + } + } + + return e + }) + + tree.SetSelectedFunc(func(node *tview.TreeNode) { + node.SetExpanded(!node.IsExpanded()) + }) + + return tree + +} + +func log(text string) { + + f, err := os.OpenFile("message.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + + if err != nil { + panic(err) + } + + if _, err := f.Write([]byte(text)); err != nil { + panic(err) + } + + if err := f.Close(); err != nil { + panic(err) + } + +}