├── .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 |
--------------------------------------------------------------------------------