├── .gitignore ├── README.md ├── go.mod ├── Makefile ├── go.sum ├── keys └── keys.go ├── main.go ├── info └── info.go ├── picom ├── picomopts.go └── picom.go ├── utils └── utils.go └── options └── options.go /.gitignore: -------------------------------------------------------------------------------- 1 | physettings 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## PhyOS System Settings Application 2 | ### Tweak your settings and customization, choose animations 3 | 4 | ### Screenshots 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/FT-Labs/physettings 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/FT-Labs/tview v0.0.0-20220910203946-9d459cd52542 7 | github.com/gdamore/tcell/v2 v2.5.3 8 | ) 9 | 10 | require ( 11 | github.com/gdamore/encoding v1.0.0 // indirect 12 | github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 13 | github.com/mattn/go-runewidth v0.0.13 // indirect 14 | github.com/rivo/uniseg v0.3.4 // indirect 15 | golang.org/x/sys v0.0.0-20220318055525-2edf467146b5 // indirect 16 | golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect 17 | golang.org/x/text v0.3.7 // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROG = physettings 2 | 3 | ifndef $(GOPATH) 4 | GOPATH=$(shell go env GOPATH) 5 | export GOPATH 6 | endif 7 | 8 | rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d)) 9 | 10 | SRC = $(call rwildcard,.,*.go) 11 | 12 | PREFIX ?= /usr 13 | 14 | GOCMD = go 15 | 16 | VERSION ?= 1.0.0 17 | 18 | build: $(SRC) 19 | GOOS=linux GOARCH=amd64 ${GOCMD} build -o ${PROG} main.go 20 | 21 | deps: $(SRC) 22 | ${GOCMD} get github.com/FT-Labs/tview@9d459cd 23 | ${GOCMD} get github.com/gdamore/tcell/v2@latest 24 | 25 | clean: 26 | rm -f ${PROG} 27 | 28 | all: deps build 29 | 30 | install: 31 | mkdir -p $(DESTDIR)$(PREFIX)/bin 32 | cp -f ${PROG} $(DESTDIR)$(PREFIX)/bin 33 | chmod 755 $(DESTDIR)$(PREFIX)/bin/${PROG} 34 | 35 | uninstall: 36 | rm -f $(DESTDIR)$(PREFIX)/bin/${PROG} 37 | 38 | .PHONY: all build deps clean install uninstall 39 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/FT-Labs/tview v0.0.0-20220910203946-9d459cd52542 h1:3MAxnQIPiAFStGcYh3DGFyD5XcXqfkuPW5S6vvvPwYY= 2 | github.com/FT-Labs/tview v0.0.0-20220910203946-9d459cd52542/go.mod h1:OxQ1yrjgG8Gy9BnIbUYYVXTaeL7/VQcSgtFBsPR13hg= 3 | github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= 4 | github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= 5 | github.com/gdamore/tcell/v2 v2.5.3 h1:b9XQrT6QGbgI7JvZOJXFNczOQeIYbo8BfeSMzt2sAV0= 6 | github.com/gdamore/tcell/v2 v2.5.3/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo= 7 | github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= 8 | github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= 9 | github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= 10 | github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 11 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 12 | github.com/rivo/uniseg v0.3.4 h1:3Z3Eu6FGHZWSfNKJTOUiPatWwfc7DzJRU04jFUqJODw= 13 | github.com/rivo/uniseg v0.3.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 14 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 15 | golang.org/x/sys v0.0.0-20220318055525-2edf467146b5 h1:saXMvIOKvRFwbOMicHXr0B1uwoxq9dGmLe5ExMES6c4= 16 | golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 17 | golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 18 | golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= 19 | golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 20 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 21 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 22 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 23 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 24 | -------------------------------------------------------------------------------- /keys/keys.go: -------------------------------------------------------------------------------- 1 | package keys 2 | 3 | import ( 4 | "os/exec" 5 | "strings" 6 | "github.com/gdamore/tcell/v2" 7 | "github.com/FT-Labs/tview" 8 | ) 9 | 10 | func Keys(app *tview.Application, nextSlide func()) (title string, content tview.Primitive){ 11 | out, err := exec.Command("manfilter", "dwm").Output() 12 | 13 | if err != nil { 14 | panic("Can't read data from dwm manual page") 15 | } 16 | 17 | table := tview.NewTable(). 18 | SetBorders(true) 19 | 20 | keys := strings.Split(string(out), ";") 21 | cols, rows := 2, len(keys)/2+1 22 | table.SetFixed(cols, rows) 23 | table.SetEvaluateAllRows(true) 24 | word := 0 25 | maxC1, maxC2 := 0, 0 26 | for i := range keys { 27 | if i%2 == 0 && maxC1 < len(keys[i]) { 28 | maxC1 = len(keys[i]) 29 | } else if maxC2 < len(keys[i]) { 30 | maxC2 = len(keys[i]) 31 | } 32 | } 33 | color := tcell.ColorBlue 34 | table.SetCell(0, 0, 35 | tview.NewTableCell("[::b]KEY BINDING"). 36 | SetTextColor(color). 37 | SetAlign(tview.AlignCenter)) 38 | 39 | table.SetCell(0, 1, 40 | tview.NewTableCell("[::b]ACTION"). 41 | SetTextColor(color). 42 | SetAlign(tview.AlignCenter)) 43 | 44 | for r := 1; r < rows; r++ { 45 | for c := 0; c < cols; c++ { 46 | if c == 0 { 47 | color = tcell.ColorWhite 48 | } else { 49 | color = tcell.ColorLightGreen 50 | } 51 | table.SetCell(r, c, 52 | tview.NewTableCell(keys[word]). 53 | SetTextColor(color). 54 | SetExpansion(2). 55 | SetAlign(tview.AlignCenter)) 56 | word = (word + 1) % len(keys) 57 | } 58 | } 59 | table.Select(0, 0).SetFixed(1, 1).SetDoneFunc(func(key tcell.Key) { 60 | if key == tcell.KeyEnter { 61 | table.SetSelectable(true, true) 62 | } 63 | }).SetSelectedFunc(func(row int, column int) { 64 | table.GetCell(row, column).SetTextColor(tcell.ColorRed) 65 | table.SetSelectable(false, false) 66 | }) 67 | 68 | flex := tview.NewFlex(). 69 | SetDirection(tview.FlexColumn). 70 | AddItem(tview.NewBox(), 0, 1, false). 71 | AddItem(tview.NewFlex(). 72 | AddItem(table, 0, 1, true), maxC1 + maxC2 + 3, 2, true). 73 | AddItem(tview.NewBox(), 0, 1, false) 74 | 75 | return "  KEY SHEET ", flex 76 | } 77 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | 7 | . "github.com/FT-Labs/physettings/info" 8 | . "github.com/FT-Labs/physettings/keys" 9 | . "github.com/FT-Labs/physettings/options" 10 | . "github.com/FT-Labs/physettings/picom" 11 | "github.com/FT-Labs/physettings/utils" 12 | "github.com/FT-Labs/tview" 13 | "github.com/gdamore/tcell/v2" 14 | ) 15 | 16 | 17 | type Slide func(app *tview.Application, nextSlide func()) (title string, content tview.Primitive) 18 | 19 | 20 | var app = tview.NewApplication() 21 | 22 | func main() { 23 | // Get global attributes 24 | utils.FetchAttributes() 25 | slides := []Slide{ 26 | Cover, 27 | Keys, 28 | Options, 29 | Picom, 30 | } 31 | 32 | pages := tview.NewPages() 33 | 34 | info := tview.NewTextView(). 35 | SetDynamicColors(true). 36 | SetRegions(true). 37 | SetWrap(false). 38 | SetHighlightedFunc(func(added, removed, remaining []string){ 39 | pages.SwitchToPage(added[0]) 40 | }) 41 | 42 | // Create the pages for all slides. 43 | previousSlide := func() { 44 | slide, _ := strconv.Atoi(info.GetHighlights()[0]) 45 | slide = (slide - 1 + len(slides)) % len(slides) 46 | info.Highlight(strconv.Itoa(slide)). 47 | ScrollToHighlight() 48 | } 49 | nextSlide := func() { 50 | slide, _ := strconv.Atoi(info.GetHighlights()[0]) 51 | slide = (slide + 1) % len(slides) 52 | info.Highlight(strconv.Itoa(slide)). 53 | ScrollToHighlight() 54 | } 55 | chooseSlide := func(s int) { 56 | info.Highlight(strconv.Itoa(s)). 57 | ScrollToHighlight() 58 | } 59 | 60 | for index, slide := range slides { 61 | title, primitive := slide(app, nextSlide) 62 | pages.AddPage(strconv.Itoa(index), primitive, true, index == 0) 63 | fmt.Fprintf(info, `F%d ["%d"][darkcyan]%s[white][""] `, index+1, index, title) 64 | } 65 | info.Highlight("0") 66 | 67 | layout := tview.NewFlex(). 68 | SetDirection(tview.FlexRow). 69 | AddItem(pages, 0, 1, true). 70 | AddItem(info, 1, 1, false) 71 | 72 | // Shortcuts to navigate the slides. 73 | app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { 74 | if event.Key() == tcell.KeyCtrlN { 75 | nextSlide() 76 | return nil 77 | } else if event.Key() == tcell.KeyCtrlP { 78 | previousSlide() 79 | return nil 80 | } else if event.Key() >= tcell.KeyF1 && event.Key() <= tcell.KeyF9 { 81 | i := event.Key() - tcell.KeyF1 82 | chooseSlide(int(i)) 83 | return nil 84 | } 85 | return event 86 | }) 87 | 88 | // Start the application. 89 | if err := app.SetRoot(layout, true).EnableMouse(true).Run(); err != nil { 90 | panic(err) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /info/info.go: -------------------------------------------------------------------------------- 1 | package info 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/gdamore/tcell/v2" 8 | "github.com/FT-Labs/tview" 9 | ) 10 | 11 | const logo = ` 12 | #######################+=###- 13 | .=+++++++++++++++=*###=+###. 14 | +#############==###-*##+ 15 | =###+=+++---:+##*-###= 16 | :###=+###..*##+=###- 17 | .*##+=###-+#=+##*. 18 | +##*-###+:*##+ 19 | =###-*#####= 20 | :###==###: 21 | .*##+-*. 22 | +##+ 23 | -= 24 | ` 25 | 26 | const ftl = ` 27 | ______________ 28 | / ____/_ __/ / 29 | / /_ / / / / 30 | / __/ / / / /___ 31 | /_/ /_/ /_____/ 32 | ` 33 | 34 | const ( 35 | subtitle = `phyOS - Settings & Usage Guide` 36 | navigation = `[F1 .. F9]: Choose page Ctrl+N: Next page Ctrl+P: Previous page Ctrl+C: Exit` 37 | zoom = `Alt+Shift+J to zoom out Alt+Shift+K to zoom in Alt+; to cycle fonts` 38 | mouse = `Or use mouse` 39 | ) 40 | 41 | 42 | // Cover returns the cover page. 43 | func Cover(app *tview.Application, nextSlide func()) (title string, content tview.Primitive) { 44 | // What's the size of the logo? 45 | lines := strings.Split(logo, "\n") 46 | logoWidth := 0 47 | logoHeight := len(lines) 48 | for _, line := range lines { 49 | if len(line) > logoWidth { 50 | logoWidth = len(line) 51 | } 52 | } 53 | lines = strings.Split(ftl, "\n") 54 | ftlWidth := 0 55 | ftlHeight := len(lines) 56 | for _, line := range lines { 57 | if len(line) > ftlWidth { 58 | ftlWidth = len(line) 59 | } 60 | } 61 | 62 | logoBox := tview.NewTextView(). 63 | SetTextColor(tcell.Color111). 64 | SetDoneFunc(func(key tcell.Key) { 65 | nextSlide() 66 | }) 67 | ftlBox := tview.NewTextView(). 68 | SetTextColor(tcell.Color116) 69 | fmt.Fprint(logoBox, logo) 70 | fmt.Fprint(ftlBox, ftl) 71 | 72 | // Create a frame for the subtitle and navigation infos. 73 | 74 | frame := tview.NewFrame(tview.NewBox()). 75 | SetBorders(0, 0, 0, 0, 0, 0). 76 | AddText(subtitle, true, tview.AlignCenter, tcell.ColorWhite). 77 | AddText("", true, tview.AlignCenter, tcell.ColorWhite). 78 | AddText(navigation, true, tview.AlignCenter, tcell.ColorDarkMagenta). 79 | AddText(mouse, true, tview.AlignCenter, tcell.ColorDarkMagenta). 80 | AddText("", true, tview.AlignCenter, tcell.ColorDarkMagenta). 81 | AddText(zoom, true, tview.AlignCenter, tcell.ColorDarkCyan) 82 | 83 | // Create a Flex layout that centers the logo and subtitle. 84 | flex := tview.NewFlex(). 85 | SetDirection(tview.FlexRow). 86 | AddItem(tview.NewBox(), 0, 4, false). 87 | AddItem(tview.NewFlex(). 88 | AddItem(tview.NewBox(), 0, 1, false). 89 | AddItem(logoBox, logoWidth, 1, true). 90 | AddItem(tview.NewBox(), 0, 1, false), logoHeight, 1, true). 91 | AddItem(frame, 0, 5, false). 92 | AddItem(tview.NewFlex(). 93 | AddItem(tview.NewBox(), 0, 1, false). 94 | AddItem(ftlBox, ftlWidth, 1, true). 95 | AddItem(tview.NewBox(), 0, 1, false), ftlHeight, 1, false) 96 | 97 | return "  INFO ", flex 98 | } 99 | -------------------------------------------------------------------------------- /picom/picomopts.go: -------------------------------------------------------------------------------- 1 | package picom 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | "strings" 8 | ) 9 | 10 | var picomConfPath string 11 | 12 | const ( 13 | _animations = "animations" 14 | _fading = "fading" 15 | _enable_fading_next_tag = "enable-fading-next-tag" 16 | _enable_fading_prev_tag = "enable-fading-prev-tag" 17 | _animation_stiffness_in_tag = "animation-stiffness-in-tag" 18 | _animation_stiffness_tag_change = "animation-stiffness-tag-change" 19 | _animation_for_open_window = "animation-for-open-window" 20 | _animation_for_unmap_window = "animation-for-unmap-window" 21 | _animation_for_prev_tag = "animation-for-prev-tag" 22 | _animation_for_next_tag = "animation-for-next-tag" 23 | _vsync = "vsync" 24 | ) 25 | 26 | var picomOpts = map[string]string { 27 | _animations : "false", 28 | _fading : "false", 29 | _animation_stiffness_in_tag : "0", 30 | _animation_stiffness_tag_change : "0", 31 | _animation_for_open_window : "none", 32 | _animation_for_unmap_window : "none", 33 | _animation_for_prev_tag : "none", 34 | _animation_for_next_tag : "none", 35 | _enable_fading_next_tag : "false", 36 | _enable_fading_prev_tag : "false", 37 | _vsync : "false", 38 | } 39 | 40 | var animInfo = map[string]string { 41 | "fly-in" : "Windows fly in from random directions to the screen.", 42 | "maximize" : "Windows pop from center of the screen to their respective positions.", 43 | "minimize" : "Windows minimize from their position to the center of the screen.", 44 | "slide-in-center" : "Windows move from upper-center of the screen to their respective positions.", 45 | "slide-out-center" : "Windows move to the upper-center of the screen.", 46 | "slide-left" : "Windows are created from the right-most window position and slide leftwards.", 47 | "slide-right" : "Windows are created from the left-most window position and slide rightwards.", 48 | "slide-down" : "Windows are moved from the top of the screen and slide downward.", 49 | "slide-up" : "Windows are moved from their position to top of the screen.", 50 | "squeeze" : "Windows are either closed or created to/from their center y-position (the animation is similar to a blinking eye).", 51 | "squeeze-bottom" : "Similar to squeeze, but the animation starts from bottom-most y-position.", 52 | "zoom" : "Windows are either created or destroyed from/to their center (not the screen center).", 53 | } 54 | 55 | var animOpenOpts = []string{ 56 | "fly-in", 57 | "slide-up", 58 | "slide-down", 59 | "slide-left", 60 | "slide-right", 61 | "squeeze", 62 | "squeeze-bottom", 63 | "zoom", 64 | } 65 | 66 | var animCloseOpts = []string{ 67 | "slide-out-center", 68 | "squeeze", 69 | "squeeze-bottom", 70 | "zoom", 71 | } 72 | 73 | var animPrevOpts = []string{ 74 | "minimize", 75 | "slide-out-center", 76 | "slide-down", 77 | "slide-up", 78 | "squeeze", 79 | "squeeze-bottom", 80 | "zoom", 81 | } 82 | 83 | var animNextOpts = []string { 84 | "fly-in", 85 | "maximize", 86 | "slide-in-center", 87 | "slide-down", 88 | "slide-up", 89 | "squeeze", 90 | "squeeze-bottom", 91 | "zoom", 92 | } 93 | 94 | func changePicomAttribute(attribute, value string, isString bool) error { 95 | picomOpts[attribute] = value 96 | var cmd string 97 | if isString { 98 | cmd = fmt.Sprintf("sed -i '/%s/c\\%s = \"%s\";' /tmp/picom.conf", attribute + "\\ =", attribute, value) 99 | } else { 100 | cmd = fmt.Sprintf("sed -i '/%s/c\\%s = %s;' /tmp/picom.conf", attribute + "\\ =", attribute, value) 101 | } 102 | err := exec.Command("/bin/bash", "-c", cmd).Run() 103 | 104 | return err 105 | } 106 | 107 | func readPicomOpts() { 108 | home, _ := os.UserHomeDir(); home += "/.config/picom/picom.conf" 109 | picomConfPath = home 110 | cmd := fmt.Sprintf("cp -f %s /tmp/picom.conf", home) 111 | exec.Command("/bin/bash", "-c", cmd).Start() 112 | for key := range picomOpts { 113 | var cmd string 114 | if key == _fading { 115 | cmd = fmt.Sprintf("grep -w \"%s\" \"%s\" | cut -f1 -d \";\" | tr -d '\"\\n'", "fading =", picomConfPath) 116 | } else if key == _vsync { 117 | cmd = fmt.Sprintf("grep -w \"%s\" \"%s\" | cut -f1 -d \";\" | tr -d '\"\\n'", "vsync =", picomConfPath) 118 | } else { 119 | cmd = fmt.Sprintf("grep -r \"%s\" \"%s\" | cut -f1 -d \";\" | tr -d '\"\\n'", key, picomConfPath) 120 | } 121 | out, err := exec.Command("/bin/bash", "-c", cmd).Output() 122 | if err != nil { 123 | fmt.Fprintf(os.Stderr, err.Error()) 124 | } else { 125 | s := strings.ReplaceAll(string(out), " ", "") 126 | arr := strings.Split(s, "=") 127 | if len(arr) > 1 { 128 | picomOpts[key] = arr[1] 129 | } 130 | 131 | search := func(cur string, arr []string) { 132 | for i := 0; i < len(arr); i++ { 133 | if arr[i] == cur { 134 | arr[0], arr[i] = arr[i], arr[0] 135 | break 136 | } 137 | } 138 | } 139 | 140 | switch key { 141 | case _animation_for_open_window: 142 | search(arr[1], animOpenOpts) 143 | case _animation_for_unmap_window: 144 | search(arr[1], animCloseOpts) 145 | case _animation_for_next_tag: 146 | search(arr[1], animNextOpts) 147 | case _animation_for_prev_tag: 148 | search(arr[1], animPrevOpts) 149 | 150 | } 151 | } 152 | } 153 | } 154 | 155 | func savePicomOpts() error { 156 | cmd := fmt.Sprintf("cp -f /tmp/picom.conf %s", picomConfPath) 157 | err := exec.Command("/bin/bash", "-c", cmd).Run() 158 | 159 | if err != nil { 160 | return err 161 | } 162 | return nil 163 | } 164 | -------------------------------------------------------------------------------- /utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "fmt" 7 | "io/ioutil" 8 | "os" 9 | "os/exec" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | const( 15 | ROFI_COLOR = "ROFI_COLOR" 16 | POWERMENU_TYPE = "POWERMENU_TYPE" 17 | POWERMENU_STYLE = "POWERMENU_STYLE" 18 | POWERMENU_CONFIRM = "POWERMENU_CONFIRM" 19 | 20 | PICOM_EXPERIMENTAL = "PICOM_EXPERIMENTAL" 21 | 22 | POS_MAKE_BAR = "pOS-make-bar" 23 | POS_GRUB_CHOOSE_THEME = "pOS-grub-choose-theme" 24 | POS_SDDM_CHOOSE_THEME = "pOS-sddm-choose-theme" 25 | 26 | PLYMOUTH = "PLYMOUTH" 27 | ) 28 | 29 | var settingsPath string 30 | // GLOBAL VARIABLES 31 | var Attrs map[string]string 32 | var RofiColors []string 33 | var PowerMenuTypes []string 34 | var PowerMenuStyles []string 35 | var ScriptInfo map[string]string 36 | 37 | func appendAttribute(attribute string) error { 38 | cmd := fmt.Sprintf("echo %s >> %s", attribute, settingsPath) 39 | return exec.Command("/bin/bash", "-c", cmd).Run() 40 | } 41 | 42 | func ChangeAttribute(attribute, value string) { 43 | cmd := fmt.Sprintf("sed -i '/%s/c\\%s=%s' %s", attribute, attribute, value, settingsPath) 44 | err := exec.Command("/bin/bash", "-c", cmd).Run() 45 | 46 | if err != nil { 47 | panic("Error occurred changing attribute") 48 | } 49 | 50 | if attribute == "CONKY_WIDGETS" { 51 | exec.Command("/usr/bin/nohup", "pOS-conky").Start() 52 | } else if attribute == "PICOM_EXPERIMENTAL" { 53 | exec.Command("killall", "-9", "picom").Run() 54 | time.Sleep(time.Millisecond * 200) 55 | exec.Command("/usr/bin/nohup", "pOS-compositor").Start() 56 | } 57 | } 58 | 59 | func fetchPowerMenuTypes() ([]string) { 60 | f, _ := ioutil.ReadDir("/usr/share/phyos/config/rofi/powermenu") 61 | types := []string{"Default"} 62 | for i := 1; i < len(f); i++ { 63 | types = append(types, fmt.Sprintf("type-%d", i)) 64 | if types[i] == Attrs[POWERMENU_TYPE] { 65 | types[0], types[i] = types[i], types[0] 66 | } 67 | } 68 | return types 69 | } 70 | 71 | 72 | func fetchRofiColors() []string { 73 | var s string 74 | const path string = "/usr/share/phyos/config/rofi/colors" 75 | cmd := "file ~/.config/rofi/colors.rasi | tr \"/.\" \" \" | awk '{print $(NF-1)}'" 76 | out, err := exec.Command("/bin/bash", "-c", cmd).Output() 77 | 78 | if err != nil { 79 | s = "None" 80 | } else { 81 | s = strings.Trim(string(out)," \n") 82 | } 83 | cmd = "ls /usr/share/phyos/config/rofi/colors/ | sed -e 's/\\.rasi$//'" 84 | out, _ = exec.Command("/bin/bash", "-c", cmd).Output() 85 | colors := strings.Split(string(out), "\n") 86 | for i:= range colors { 87 | if colors[i] == s { 88 | colors[0], colors[i] = colors[i], colors[0] 89 | break 90 | } 91 | } 92 | return colors[:len(colors) - 1] 93 | } 94 | 95 | func fetchScriptInfo() map[string]string { 96 | m := make(map[string]string) 97 | out, err := exec.Command("manfilter", "phyos", "CUSTOMIZATION", "SCRIPTS").Output() 98 | 99 | if err != nil { 100 | panic("Can't fetch script data") 101 | } 102 | 103 | scriptInfo := strings.Split(string(out), ";") 104 | 105 | for i := 0; i < len(scriptInfo) - 1; i += 2 { 106 | m[scriptInfo[i]] = scriptInfo[i + 1] 107 | } 108 | return m 109 | } 110 | 111 | func SetAttribute(attribute, value string) error { 112 | if key, ok := Attrs[attribute]; ok { 113 | ChangeAttribute(attribute, value) 114 | Attrs[key] = attribute 115 | return nil 116 | } 117 | return errors.New("Can't get attribute") 118 | } 119 | 120 | func SetRofiColor(c string) { 121 | cmd := fmt.Sprintf("ln -sf /usr/share/phyos/config/rofi/colors/%s.rasi ~/.config/rofi/colors.rasi", c) 122 | exec.Command("/bin/bash", "-c", cmd).Start() 123 | } 124 | 125 | func RunScript(c string) error { 126 | const TERM_TITLE = "physet-run" 127 | const GEOM = "80x30" 128 | err := exec.Command("st", "-n", TERM_TITLE, "-g", GEOM, "-e", c).Run() 129 | 130 | if err != nil { 131 | return err 132 | } 133 | return nil 134 | } 135 | 136 | func FetchAttributes() { 137 | Attrs = make(map[string]string) 138 | home, err := os.UserHomeDir() 139 | 140 | if err != nil { 141 | panic(err) 142 | } 143 | settingsPath = fmt.Sprintf("%s/.config/phyos/phyos.conf", home) 144 | settingsDefaultPath := fmt.Sprintf("%s/.config/phyos/phyos.conf.default", home) 145 | f, err := os.Open(settingsPath) 146 | 147 | if err != nil { 148 | panic("Can't open user settings file") 149 | } 150 | 151 | sc := bufio.NewScanner(f) 152 | 153 | for sc.Scan() { 154 | l := strings.ReplaceAll(sc.Text(), "\n", "") 155 | 156 | if strings.Contains(l, "=") { 157 | arr := strings.Split(l, "=") 158 | if len(arr) == 1 { 159 | Attrs[arr[0]] = "" 160 | } else { 161 | Attrs[arr[0]] = arr[1] 162 | } 163 | } 164 | } 165 | if err := sc.Err(); err != nil { 166 | panic(err) 167 | } 168 | f.Close() 169 | f, err = os.Open(settingsDefaultPath) 170 | 171 | sc = bufio.NewScanner(f) 172 | 173 | if err != nil { 174 | panic("Can't open default settings file") 175 | } 176 | 177 | for sc.Scan() { 178 | l := strings.ReplaceAll(sc.Text(), "\n", "") 179 | 180 | if strings.Contains(l, "=") { 181 | arr := strings.Split(l, "=") 182 | if _, ok := Attrs[arr[0]]; !ok { 183 | err := appendAttribute(l) 184 | if len(arr) > 1 { 185 | Attrs[arr[0]] = arr[1] 186 | } 187 | if err != nil { 188 | fmt.Fprintf(os.Stderr, err.Error()) 189 | } 190 | } 191 | } 192 | } 193 | 194 | f.Close() 195 | 196 | PowerMenuTypes = fetchPowerMenuTypes() 197 | RofiColors = fetchRofiColors() 198 | PowerMenuStyles = append(PowerMenuStyles, "style-1", "style-2", "style-3", "style-4", "style-5") 199 | ScriptInfo = fetchScriptInfo() 200 | 201 | for i := range PowerMenuStyles { 202 | if PowerMenuStyles[i] == Attrs[POWERMENU_STYLE] { 203 | PowerMenuStyles[0], PowerMenuStyles[i] = PowerMenuStyles[i], PowerMenuStyles[0] 204 | break 205 | } 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /options/options.go: -------------------------------------------------------------------------------- 1 | package options 2 | 3 | import ( 4 | "fmt" 5 | "os/exec" 6 | "strings" 7 | "time" 8 | 9 | u "github.com/FT-Labs/physettings/utils" 10 | "github.com/FT-Labs/tview" 11 | "github.com/gdamore/tcell/v2" 12 | ) 13 | 14 | var app *tview.Application 15 | var pages *tview.Pages 16 | var confirm *tview.Modal 17 | var scriptInfo *tview.TextView 18 | var scriptInfoLast string 19 | 20 | var lastFocus tview.Primitive 21 | var o1, o2 *tview.Form 22 | var scriptRunning = false 23 | 24 | func buttonSelGrubTheme() { 25 | err := u.RunScript(u.POS_GRUB_CHOOSE_THEME) 26 | if err != nil { 27 | confirm.SetText(err.Error()). 28 | SetBackgroundColor(tcell.Color59). 29 | SetTextColor(tcell.ColorRed) 30 | } else { 31 | confirm.SetText("Succesfully changed grub theme"). 32 | SetBackgroundColor(tcell.Color59). 33 | SetTextColor(tcell.ColorLightGreen) 34 | } 35 | pages.ShowPage("confirm") 36 | } 37 | 38 | func buttonSelSddmTheme() { 39 | err := u.RunScript(u.POS_SDDM_CHOOSE_THEME) 40 | if err != nil { 41 | confirm.SetText(err.Error()). 42 | SetBackgroundColor(tcell.Color59). 43 | SetTextColor(tcell.ColorRed) 44 | } else { 45 | confirm.SetText("Succesfully changed sddm theme"). 46 | SetBackgroundColor(tcell.Color59). 47 | SetTextColor(tcell.ColorLightGreen) 48 | } 49 | pages.ShowPage("confirm") 50 | } 51 | 52 | func buttonSelMakeBar() { 53 | err := u.RunScript(u.POS_MAKE_BAR) 54 | if err != nil { 55 | confirm.SetText(err.Error()). 56 | SetBackgroundColor(tcell.Color59). 57 | SetTextColor(tcell.ColorRed) 58 | } else { 59 | confirm.SetText("Succesfully updated statusbar"). 60 | SetBackgroundColor(tcell.Color59). 61 | SetTextColor(tcell.ColorLightGreen) 62 | } 63 | pages.ShowPage("confirm") 64 | } 65 | func buttonSelPdwm() { 66 | exec.Command("pdwmc", "-q").Run() 67 | } 68 | 69 | func checkSelShutdownConfirm(checked bool) { 70 | if checked { 71 | u.SetAttribute(u.POWERMENU_CONFIRM, "true") 72 | } else { 73 | u.SetAttribute(u.POWERMENU_CONFIRM, "false") 74 | } 75 | } 76 | 77 | func dropSelRofiColor(selection string, i int) { 78 | u.SetRofiColor(selection) 79 | confirm.SetText("Rofi colorscheme changed to: " + selection). 80 | SetBackgroundColor(tcell.Color59). 81 | SetTextColor(tcell.ColorLightGreen) 82 | pages.ShowPage("confirm") 83 | } 84 | 85 | func dropSelPowerMenuType(selection string, i int) { 86 | err := u.SetAttribute(u.POWERMENU_TYPE, selection) 87 | if err != nil { 88 | confirm.SetText("Failed to set powermenu type"). 89 | SetBackgroundColor(tcell.Color59). 90 | SetTextColor(tcell.ColorRed) 91 | } else { 92 | confirm.SetText("Powermenu type changed to: " + selection). 93 | SetBackgroundColor(tcell.Color59). 94 | SetTextColor(tcell.ColorLightGreen) 95 | } 96 | pages.ShowPage("confirm") 97 | } 98 | 99 | func dropSelPowerMenuStyle(selection string, i int) { 100 | err := u.SetAttribute(u.POWERMENU_STYLE, selection) 101 | if err != nil { 102 | confirm.SetText("Failed to set powermenu style"). 103 | SetBackgroundColor(tcell.Color59). 104 | SetTextColor(tcell.ColorRed) 105 | } else { 106 | confirm.SetText("Powermenu style changed to: " + selection). 107 | SetBackgroundColor(tcell.Color59). 108 | SetTextColor(tcell.ColorLightGreen) 109 | } 110 | pages.ShowPage("confirm") 111 | } 112 | 113 | 114 | func makeDropdown(opt string) *tview.DropDown { 115 | switch opt { 116 | case u.ROFI_COLOR: 117 | d := tview.NewDropDown(). 118 | SetLabel("ROFI_COLOR: "). 119 | SetOptions(u.RofiColors, dropSelRofiColor). 120 | SetCurrentOption(0) 121 | d.SetFocusFunc(func(){ 122 | scriptInfoLast = printScriptInfo("Set colorscheme of powermenu.") 123 | }) 124 | return d 125 | case u.POWERMENU_STYLE: 126 | d := tview.NewDropDown(). 127 | SetLabel(u.POWERMENU_STYLE + " : "). 128 | SetOptions(u.PowerMenuStyles, dropSelPowerMenuStyle). 129 | SetCurrentOption(0) 130 | d.SetFocusFunc(func() { 131 | scriptInfoLast = printScriptInfo("Change powermenu style, which only rearranges items. Looks will be similar, but properties will be changed according to powermenu type.") 132 | }) 133 | return d 134 | default: 135 | d := tview.NewDropDown(). 136 | SetLabel(u.POWERMENU_TYPE + " : "). 137 | SetOptions(u.PowerMenuTypes, dropSelPowerMenuType). 138 | SetCurrentOption(0) 139 | d.SetFocusFunc(func() { 140 | scriptInfoLast = printScriptInfo("Change the type of powermenu. This will change the display of powermenu.") 141 | }) 142 | return d 143 | } 144 | } 145 | 146 | func makeScriptsInfoTextView() { 147 | scriptInfo = tview.NewTextView(). 148 | SetDynamicColors(true). 149 | SetWordWrap(true). 150 | SetRegions(true). 151 | SetChangedFunc(func() { 152 | app.Draw() 153 | }) 154 | } 155 | 156 | func printScriptInfo(s string) string { 157 | if s == scriptInfoLast { 158 | return s 159 | } 160 | run := func() { 161 | scriptInfo.Clear() 162 | arr := strings.Split(s, " ") 163 | for _, word := range arr { 164 | for i := 0; i < 20; i++ { 165 | time.Sleep(time.Millisecond) 166 | if !scriptRunning { 167 | return 168 | } 169 | } 170 | fmt.Fprintf(scriptInfo, "%s ", word) 171 | } 172 | } 173 | 174 | if scriptRunning { 175 | scriptRunning = false 176 | time.Sleep(time.Millisecond * 2) 177 | printScriptInfo(s) 178 | } else { 179 | scriptRunning = true 180 | go run() 181 | } 182 | return s 183 | } 184 | 185 | func makeOptionsForm() *tview.Form { 186 | c := tview.NewCheckbox(). 187 | SetLabel("ASK ON SHUTDOWN :"). 188 | SetChecked(u.Attrs[u.POWERMENU_CONFIRM] == "true"). 189 | SetChangedFunc(checkSelShutdownConfirm) 190 | 191 | c.SetFocusFunc(func(){ 192 | scriptInfoLast = printScriptInfo("If selected, a confirmation prompt will appear when shutting down or rebooting the computer.") 193 | }) 194 | 195 | return tview.NewForm(). 196 | SetFieldBackgroundColor(tcell.Color238). 197 | SetFieldTextColor(tcell.Color255). 198 | SetLabelColor(tcell.Color33). 199 | SetItemPadding(3). 200 | AddDropDown(makeDropdown(u.ROFI_COLOR)). 201 | AddDropDown(makeDropdown(u.POWERMENU_TYPE)). 202 | AddDropDown(makeDropdown(u.POWERMENU_STYLE)). 203 | AddCheckbox(c) 204 | } 205 | 206 | func makeScriptsForm() *tview.Form { 207 | bGrub := tview.NewButton(u.POS_GRUB_CHOOSE_THEME). 208 | SetSelectedFunc(buttonSelGrubTheme). 209 | SetLabelColorActivated(tcell.Color238) 210 | bSddm := tview.NewButton(u.POS_SDDM_CHOOSE_THEME). 211 | SetSelectedFunc(buttonSelSddmTheme). 212 | SetLabelColorActivated(tcell.Color238) 213 | bBar := tview.NewButton(u.POS_MAKE_BAR). 214 | SetSelectedFunc(buttonSelMakeBar). 215 | SetLabelColorActivated(tcell.Color238) 216 | bPdwm := tview.NewButton("pdwm Control Center"). 217 | SetSelectedFunc(buttonSelPdwm). 218 | SetLabelColorActivated(tcell.Color238) 219 | 220 | bGrub.SetFocusFunc(func(){ 221 | scriptInfoLast = printScriptInfo(u.ScriptInfo[u.POS_GRUB_CHOOSE_THEME]) 222 | }) 223 | bSddm.SetFocusFunc(func(){ 224 | scriptInfoLast = printScriptInfo(u.ScriptInfo[u.POS_SDDM_CHOOSE_THEME]) 225 | }) 226 | bBar.SetFocusFunc(func(){ 227 | scriptInfoLast = printScriptInfo(u.ScriptInfo[u.POS_MAKE_BAR]) 228 | }) 229 | bPdwm.SetFocusFunc(func(){ 230 | scriptInfoLast = printScriptInfo("Change pdwm keybinds, colorscheme, rules, buttons or appearance.\nPlease note that this works only with 'pdwm', phyOS-dwm is not configurable without changing source code.") 231 | }) 232 | return tview.NewForm(). 233 | SetItemPadding(3). 234 | SetFieldBackgroundColor(tcell.Color238). 235 | SetFieldTextColor(tcell.Color255). 236 | SetLabelColor(tcell.Color111). 237 | AddButtonItem(bGrub, true). 238 | AddButtonItem(bSddm, true). 239 | AddButtonItem(bBar, true). 240 | AddButtonItem(bPdwm, true) 241 | } 242 | 243 | 244 | func Options(a *tview.Application,nextSlide func()) (title string, content tview.Primitive){ 245 | app = a 246 | makeScriptsInfoTextView() 247 | confirm = tview.NewModal(). 248 | AddButtons([]string{"OK"}).SetDoneFunc(func(buttonIndex int, buttonLabel string) { 249 | pages.HidePage("confirm") 250 | if lastFocus != nil && lastFocus != app.GetFocus() { 251 | app.SetFocus(lastFocus) 252 | } 253 | }) 254 | 255 | pages = tview.NewPages() 256 | newPrimitive := func(text string) tview.Primitive { 257 | if text != "" { 258 | return tview.NewFrame(nil). 259 | SetBorders(0, 0, 0, 0, 0, 0). 260 | AddText(text, true, tview.AlignCenter, tcell.ColorWhite) 261 | } else { 262 | o1 = makeOptionsForm() 263 | o2 = makeScriptsForm() 264 | 265 | o1.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { 266 | if event.Key() == tcell.KeyLeft || event.Key() == tcell.KeyRight { 267 | app.SetFocus(o2) 268 | lastFocus = o2 269 | return nil 270 | } 271 | return event 272 | }) 273 | 274 | o2.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { 275 | if event.Key() == tcell.KeyLeft || event.Key() == tcell.KeyRight { 276 | app.SetFocus(o1) 277 | lastFocus = o1 278 | return nil 279 | } 280 | return event 281 | }) 282 | 283 | return tview.NewGrid(). 284 | SetBordersColor(tcell.Color33). 285 | SetBorders(true). 286 | AddItem(tview.NewFlex(). 287 | SetDirection(tview.FlexRow). 288 | AddItem(scriptInfo, 0, 3, false). 289 | AddItem(tview.NewFlex(). 290 | SetDirection(tview.FlexColumn). 291 | AddItem(o1, 0, 3, true). 292 | AddItem(o2, 0, 3, true), 0, 6, true), 0, 0, 1, 1, 0, 0, true) 293 | } 294 | } 295 | 296 | flex := tview.NewFlex(). 297 | SetDirection(tview.FlexRow). 298 | AddItem(tview.NewBox(), 0, 1, false). 299 | AddItem(newPrimitive("[::b]SET OPTIONS 漣"), 0, 1, false). 300 | AddItem(tview.NewFlex(). 301 | SetDirection(tview.FlexColumn). 302 | AddItem(tview.NewBox(), 0, 3, false). 303 | AddItem(newPrimitive(""), 0, 9, true). 304 | AddItem(tview.NewBox(), 0, 3, false), 0, 16, true). 305 | AddItem(newPrimitive("Use Tab or Up-Down keys to navigate, Shift+Tab or Left-Right to navigate between columns"), 0, 1, false). 306 | AddItem(newPrimitive("Type to search and Enter to select, Esc to cancel selection"), 0, 1, false) 307 | 308 | pages.AddPage("flex", flex, true, true). 309 | AddPage("confirm", confirm, true, false) 310 | 311 | return " 煉 OPTIONS ", pages 312 | } 313 | -------------------------------------------------------------------------------- /picom/picom.go: -------------------------------------------------------------------------------- 1 | package picom 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "time" 7 | 8 | u "github.com/FT-Labs/physettings/utils" 9 | "github.com/FT-Labs/tview" 10 | "github.com/gdamore/tcell/v2" 11 | ) 12 | 13 | var app *tview.Application 14 | var pages *tview.Pages 15 | var confirm *tview.Modal 16 | var scriptInfo *tview.TextView 17 | var scriptInfoLast string 18 | var scriptRunning bool = false 19 | 20 | var lastFocus tview.Primitive 21 | var o1, o2 *tview.Form 22 | 23 | func checkSelAnimConfirm(checked bool) { 24 | if checked { 25 | changePicomAttribute(_animations, "true", false) 26 | } else { 27 | changePicomAttribute(_animations, "false", false) 28 | } 29 | } 30 | 31 | func checkSelExperimental(checked bool) { 32 | if checked { 33 | u.SetAttribute(u.PICOM_EXPERIMENTAL, "true") 34 | changePicomAttribute(u.PICOM_EXPERIMENTAL, "true", false) 35 | } else { 36 | u.SetAttribute(u.PICOM_EXPERIMENTAL, "false") 37 | changePicomAttribute(u.PICOM_EXPERIMENTAL, "false", false) 38 | } 39 | } 40 | 41 | func checkSelVsync(checked bool) { 42 | if checked { 43 | changePicomAttribute(_vsync, "true", false) 44 | } else { 45 | changePicomAttribute(_vsync, "false", false) 46 | } 47 | } 48 | 49 | func checkSelFadeConfirm(checked bool) { 50 | if checked { 51 | changePicomAttribute(_fading, "true", false) 52 | } else { 53 | changePicomAttribute(_fading, "false", false) 54 | } 55 | } 56 | 57 | func checkSelFadeNextTag(checked bool) { 58 | if checked { 59 | changePicomAttribute(_enable_fading_next_tag, "true", false) 60 | } else { 61 | changePicomAttribute(_enable_fading_next_tag, "false", false) 62 | } 63 | } 64 | 65 | func checkSelFadePrevTag(checked bool) { 66 | if checked { 67 | changePicomAttribute(_enable_fading_prev_tag, "true", false) 68 | } else { 69 | changePicomAttribute(_enable_fading_prev_tag, "false", false) 70 | } 71 | } 72 | 73 | func dropSelOpenWindowAnim(selection string, i int) { 74 | err := changePicomAttribute(_animation_for_open_window, selection, true) 75 | if err != nil { 76 | confirm.SetText(err.Error()). 77 | SetBackgroundColor(tcell.Color59). 78 | SetTextColor(tcell.ColorRed) 79 | } else { 80 | confirm.SetText("Open window animation changed to: " + selection). 81 | SetBackgroundColor(tcell.Color59). 82 | SetTextColor(tcell.ColorLightGreen) 83 | } 84 | pages.ShowPage("confirm") 85 | } 86 | 87 | func dropSelCloseWindowAnim(selection string, i int) { 88 | err := changePicomAttribute(_animation_for_unmap_window, selection, true) 89 | if err != nil { 90 | confirm.SetText(err.Error()). 91 | SetBackgroundColor(tcell.Color59). 92 | SetTextColor(tcell.ColorRed) 93 | } else { 94 | confirm.SetText("Open window animation changed to: " + selection). 95 | SetBackgroundColor(tcell.Color59). 96 | SetTextColor(tcell.ColorLightGreen) 97 | } 98 | pages.ShowPage("confirm") 99 | } 100 | 101 | func dropSelNextTagAnim(selection string, i int) { 102 | err := changePicomAttribute(_animation_for_next_tag, selection, true) 103 | if err != nil { 104 | confirm.SetText(err.Error()). 105 | SetBackgroundColor(tcell.Color59). 106 | SetTextColor(tcell.ColorRed) 107 | } else { 108 | confirm.SetText("Next tag animation change to: " + selection). 109 | SetBackgroundColor(tcell.Color59). 110 | SetTextColor(tcell.ColorLightGreen) 111 | } 112 | pages.ShowPage("confirm") 113 | } 114 | 115 | func dropSelPrevTagAnim(selection string, i int) { 116 | err := changePicomAttribute(_animation_for_prev_tag, selection, true) 117 | if err != nil { 118 | confirm.SetText(err.Error()). 119 | SetBackgroundColor(tcell.Color59). 120 | SetTextColor(tcell.ColorRed) 121 | } else { 122 | confirm.SetText("Previous tag animation change to: " + selection). 123 | SetBackgroundColor(tcell.Color59). 124 | SetTextColor(tcell.ColorLightGreen) 125 | } 126 | pages.ShowPage("confirm") 127 | } 128 | 129 | 130 | func makeDropdown(opt string) *tview.DropDown { 131 | d := tview.NewDropDown() 132 | d.List.SetChangedFunc(func(index int, mainText string, secondaryText string, shortcut rune){ 133 | scriptInfoLast = printScriptInfo(animInfo[mainText]) 134 | }) 135 | d.List.SetFocusFunc(func(){ 136 | _, s := d.GetCurrentOption() 137 | scriptInfoLast = printScriptInfo(animInfo[s]) 138 | }) 139 | switch opt { 140 | case _animation_for_open_window: 141 | d.SetLabel("OPEN WINDOW ANIM : "). 142 | SetOptions(animOpenOpts, dropSelOpenWindowAnim). 143 | SetFieldWidth(16). 144 | SetCurrentOption(0) 145 | d.SetFocusFunc(func(){ 146 | scriptInfoLast = printScriptInfo("Choose window opening animation.") 147 | }) 148 | case _animation_for_unmap_window: 149 | d.SetLabel("CLOSE WINDOW ANIM :"). 150 | SetOptions(animCloseOpts, dropSelCloseWindowAnim). 151 | SetFieldWidth(16). 152 | SetCurrentOption(0) 153 | d.SetFocusFunc(func() { 154 | scriptInfoLast = printScriptInfo("Choose window closing or unmapping animation.") 155 | }) 156 | case _animation_for_next_tag: 157 | d.SetLabel("ANIM FOR NEXT TAG :"). 158 | SetOptions(animNextOpts, dropSelNextTagAnim). 159 | SetFieldWidth(16). 160 | SetCurrentOption(0) 161 | d.SetFocusFunc(func() { 162 | scriptInfoLast = printScriptInfo("Choose animation for incoming tag windows.") 163 | }) 164 | case _animation_for_prev_tag: 165 | d.SetLabel("ANIM FOR PREV TAG :"). 166 | SetOptions(animPrevOpts, dropSelPrevTagAnim). 167 | SetFieldWidth(16). 168 | SetCurrentOption(0) 169 | d.SetFocusFunc(func() { 170 | scriptInfoLast = printScriptInfo("Choose animation for windows that are going out from current tag.") 171 | }) 172 | } 173 | return d 174 | } 175 | 176 | func makeScriptsInfoTextView() { 177 | scriptInfo = tview.NewTextView(). 178 | SetDynamicColors(true). 179 | SetWordWrap(true). 180 | SetRegions(true). 181 | SetChangedFunc(func() { 182 | app.Draw() 183 | }) 184 | } 185 | 186 | func printScriptInfo(s string) string { 187 | if s == scriptInfoLast { 188 | return s 189 | } 190 | 191 | run := func() { 192 | scriptInfo.Clear() 193 | arr := strings.Split(s, " ") 194 | for _, word := range arr { 195 | for i := 0; i < 20; i++ { 196 | time.Sleep(time.Millisecond) 197 | if !scriptRunning { 198 | return 199 | } 200 | } 201 | fmt.Fprintf(scriptInfo, "%s ", word) 202 | } 203 | } 204 | 205 | if scriptRunning { 206 | scriptRunning = false 207 | time.Sleep(time.Millisecond * 2) 208 | printScriptInfo(s) 209 | } else { 210 | scriptRunning = true 211 | go run() 212 | } 213 | return s 214 | } 215 | 216 | func makeOptionsForm() *tview.Form { 217 | 218 | c := tview.NewCheckbox(). 219 | SetLabel("EXPERIMENTAL BACKENDS:"). 220 | SetChecked(u.Attrs[u.PICOM_EXPERIMENTAL] == "true"). 221 | SetChangedFunc(checkSelExperimental) 222 | 223 | c.SetFocusFunc(func(){ 224 | scriptInfoLast = printScriptInfo("Enable experimental backends in picom.\nThis will add dual-kawase blur, which is preferred.\nNote that this uses GLX backend, which doesn't work correctly in legacy hardware.") 225 | }) 226 | 227 | c0 := tview.NewCheckbox(). 228 | SetLabel("ENABLE VSYNC :"). 229 | SetChecked(picomOpts[_vsync] == "true"). 230 | SetChangedFunc(checkSelVsync) 231 | 232 | c0.SetFocusFunc(func(){ 233 | scriptInfoLast = printScriptInfo("Enable Vsync. Recommended if you experience screen tearing.") 234 | }) 235 | 236 | c1 := tview.NewCheckbox(). 237 | SetLabel("ENABLE ANIMATIONS :"). 238 | SetChecked(picomOpts[_animations] == "true"). 239 | SetChangedFunc(checkSelAnimConfirm) 240 | 241 | c1.SetFocusFunc(func(){ 242 | scriptInfoLast = printScriptInfo("Enable or disable animations in picom") 243 | }) 244 | 245 | c2 := tview.NewCheckbox(). 246 | SetLabel("ENABLE FADING :"). 247 | SetChecked(picomOpts[_fading] == "true"). 248 | SetChangedFunc(checkSelFadeConfirm) 249 | 250 | c2.SetFocusFunc(func(){ 251 | scriptInfoLast = printScriptInfo("Enable fading when opening - closing windows.\nWindows will go from transparent to opaque if set.") 252 | }) 253 | 254 | c3 := tview.NewCheckbox(). 255 | SetLabel("NEXT TAG FADING :"). 256 | SetChecked(picomOpts[_enable_fading_next_tag] == "true"). 257 | SetChangedFunc(checkSelFadeNextTag) 258 | 259 | c3.SetFocusFunc(func(){ 260 | scriptInfoLast = printScriptInfo("Enable fading for incoming tag.\nNew windows that are coming from next tag will go from transparent to opaque.") 261 | }) 262 | 263 | c4 := tview.NewCheckbox(). 264 | SetLabel("PREV TAG FADING :"). 265 | SetChecked(picomOpts[_enable_fading_prev_tag] == "true"). 266 | SetChangedFunc(checkSelFadePrevTag) 267 | 268 | c4.SetFocusFunc(func(){ 269 | scriptInfoLast = printScriptInfo("Enable fading for next tag.\nOld windows that are going out from current tag will go from opaque to transparent.") 270 | }) 271 | 272 | i1 := tview.NewInputField(). 273 | SetLabel("ANIM SPEED IN TAG :"). 274 | SetAcceptanceFunc(tview.InputFieldFloatMaxLength(3)). 275 | SetPlaceholder(picomOpts[_animation_stiffness_in_tag]). 276 | SetFieldWidth(len(picomOpts[_animation_stiffness_in_tag])) 277 | i1.SetChangedFunc(func(text string){ 278 | if len(text) > len(picomOpts[_animation_stiffness_in_tag]) { 279 | i1.SetFieldWidth(len(text)) 280 | } else { 281 | i1.SetFieldWidth(len(picomOpts[_animation_stiffness_in_tag])) 282 | } 283 | }) 284 | 285 | i1.SetFocusFunc(func(){ 286 | scriptInfoLast = printScriptInfo("Set animation speed for moving or resizing windows in current tag.\nDefault value is [lightgreen:b]125[-:-]. Enter an integer or float number.") 287 | }) 288 | 289 | i1.SetDoneFunc(func(key tcell.Key){ 290 | switch key { 291 | case tcell.KeyEnter: 292 | err := changePicomAttribute(_animation_stiffness_in_tag, i1.GetText(), false) 293 | 294 | if err != nil { 295 | confirm.SetText(err.Error()). 296 | SetBackgroundColor(tcell.Color59). 297 | SetTextColor(tcell.ColorRed) 298 | } else { 299 | confirm.SetText("Animation speed in current tag changed to: [::b]" + i1.GetText()). 300 | SetBackgroundColor(tcell.Color59). 301 | SetTextColor(tcell.ColorLightGreen) 302 | } 303 | pages.ShowPage("confirm") 304 | } 305 | }) 306 | 307 | i2 := tview.NewInputField(). 308 | SetLabel("ANIM SPEED ON TAG CHANGE :"). 309 | SetAcceptanceFunc(tview.InputFieldFloatMaxLength(3)). 310 | SetPlaceholder(picomOpts[_animation_stiffness_tag_change]). 311 | SetFieldWidth(len(picomOpts[_animation_stiffness_tag_change])) 312 | 313 | i2.SetChangedFunc(func(text string){ 314 | if len(text) > len(picomOpts[_animation_stiffness_tag_change]) { 315 | i2.SetFieldWidth(len(text)) 316 | } else { 317 | i2.SetFieldWidth(len(picomOpts[_animation_stiffness_tag_change])) 318 | } 319 | }) 320 | 321 | i2.SetFocusFunc(func(){ 322 | scriptInfoLast = printScriptInfo("Set animation speed for windows transitioning between tags.\nDefault value is [lightgreen:b]90[-:-]. Enter an integer or float number.") 323 | }) 324 | 325 | i2.SetDoneFunc(func(key tcell.Key){ 326 | switch key { 327 | case tcell.KeyEnter: 328 | err := changePicomAttribute(_animation_stiffness_tag_change, i2.GetText(), false) 329 | 330 | if err != nil { 331 | confirm.SetText(err.Error()). 332 | SetBackgroundColor(tcell.Color59). 333 | SetTextColor(tcell.ColorRed) 334 | } else { 335 | confirm.SetText("Animation speed between tags changed to: [::b]" + i2.GetText()). 336 | SetBackgroundColor(tcell.Color59). 337 | SetTextColor(tcell.ColorLightGreen) 338 | } 339 | pages.ShowPage("confirm") 340 | } 341 | }) 342 | 343 | return tview.NewForm(). 344 | SetFieldBackgroundColor(tcell.Color238). 345 | SetFieldTextColor(tcell.Color255). 346 | SetLabelColor(tcell.Color33). 347 | SetItemPadding(1). 348 | AddCheckbox(c). 349 | AddCheckbox(c0). 350 | AddCheckbox(c1). 351 | AddCheckbox(c2). 352 | AddCheckbox(c3). 353 | AddCheckbox(c4). 354 | AddInputFieldItem(i1). 355 | AddInputFieldItem(i2) 356 | } 357 | 358 | func makeAnimationForm() *tview.Form { 359 | return tview.NewForm(). 360 | SetItemPadding(2). 361 | SetLabelColor(tcell.Color111). 362 | SetButtonsAlign(tview.AlignCenter). 363 | SetFieldBackgroundColor(tcell.Color238). 364 | SetFieldTextColor(tcell.Color255). 365 | SetButtonBackgroundColor(tcell.Color238). 366 | SetButtonTextColor(tcell.Color255). 367 | AddDropDown(makeDropdown(_animation_for_open_window)). 368 | AddDropDown(makeDropdown(_animation_for_unmap_window)). 369 | AddDropDown(makeDropdown(_animation_for_prev_tag)). 370 | AddDropDown(makeDropdown(_animation_for_next_tag)). 371 | AddButtonItem(tview.NewButton("SAVE CHANGES"). 372 | SetSelectedFunc(func(){ 373 | err := savePicomOpts() 374 | if err != nil { 375 | confirm.SetText(err.Error()). 376 | SetBackgroundColor(tcell.Color59). 377 | SetTextColor(tcell.ColorRed) 378 | } else { 379 | confirm.SetText("Picom options saved succesfully"). 380 | SetBackgroundColor(tcell.Color59). 381 | SetTextColor(tcell.ColorLightGreen) 382 | } 383 | pages.ShowPage("confirm") 384 | }), false) 385 | } 386 | 387 | 388 | func Picom(a *tview.Application,nextSlide func()) (title string, content tview.Primitive){ 389 | readPicomOpts() 390 | app = a 391 | makeScriptsInfoTextView() 392 | confirm = tview.NewModal(). 393 | AddButtons([]string{"OK"}).SetDoneFunc(func(buttonIndex int, buttonLabel string) { 394 | pages.HidePage("confirm") 395 | if lastFocus != nil && lastFocus != app.GetFocus() { 396 | app.SetFocus(lastFocus) 397 | } 398 | }) 399 | 400 | pages = tview.NewPages() 401 | newPrimitive := func(text string) tview.Primitive { 402 | if text != "" { 403 | return tview.NewFrame(nil). 404 | SetBorders(0, 0, 0, 0, 0, 0). 405 | AddText(text, true, tview.AlignCenter, tcell.ColorWhite) 406 | } else { 407 | o1 = makeOptionsForm() 408 | o2 = makeAnimationForm() 409 | 410 | o1.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { 411 | if event.Key() == tcell.KeyLeft || event.Key() == tcell.KeyRight { 412 | app.SetFocus(o2) 413 | lastFocus = o2 414 | return nil 415 | } 416 | return event 417 | }) 418 | 419 | o2.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { 420 | if event.Key() == tcell.KeyLeft || event.Key() == tcell.KeyRight { 421 | app.SetFocus(o1) 422 | lastFocus = o1 423 | return nil 424 | } 425 | return event 426 | }) 427 | 428 | return tview.NewGrid(). 429 | SetBordersColor(tcell.Color33). 430 | SetBorders(true). 431 | AddItem(tview.NewFlex(). 432 | SetDirection(tview.FlexRow). 433 | AddItem(scriptInfo, 0, 3, false). 434 | AddItem(tview.NewFlex(). 435 | SetDirection(tview.FlexColumn). 436 | AddItem(o1, 0, 3, true). 437 | AddItem(o2, 0, 3, true), 0, 6, true), 0, 0, 1, 1, 0, 0, true) 438 | } 439 | } 440 | 441 | flex := tview.NewFlex(). 442 | SetDirection(tview.FlexRow). 443 | AddItem(tview.NewBox(), 0, 1, false). 444 | AddItem(newPrimitive("[::b]SET OPTIONS 漣"), 0, 1, false). 445 | AddItem(tview.NewFlex(). 446 | SetDirection(tview.FlexColumn). 447 | AddItem(tview.NewBox(), 0, 3, false). 448 | AddItem(newPrimitive(""), 0, 9, true). 449 | AddItem(tview.NewBox(), 0, 3, false), 0, 16, true). 450 | AddItem(newPrimitive("Use Tab or Up-Down keys to navigate, Shift+Tab or Left-Right to navigate between columns"), 0, 1, false). 451 | AddItem(newPrimitive("Type to search and Enter to select, Esc to cancel selection"), 0, 1, false) 452 | 453 | pages.AddPage("flex", flex, true, true). 454 | AddPage("confirm", confirm, true, false) 455 | 456 | return " 𧻓 PICOM - ANIMATIONS ", pages 457 | } 458 | --------------------------------------------------------------------------------