1// Copyright 2019 Google Inc. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// Binary segmentdisplaydemo shows the functionality of a segment display. 16package main 17 18import ( 19 "context" 20 "strings" 21 "time" 22 23 "github.com/mum4k/termdash" 24 "github.com/mum4k/termdash/cell" 25 "github.com/mum4k/termdash/container" 26 "github.com/mum4k/termdash/linestyle" 27 "github.com/mum4k/termdash/terminal/tcell" 28 "github.com/mum4k/termdash/terminal/terminalapi" 29 "github.com/mum4k/termdash/widgets/segmentdisplay" 30) 31 32// clock displays the current time on the segment display. 33// Exists when the context expires. 34func clock(ctx context.Context, sd *segmentdisplay.SegmentDisplay) { 35 ticker := time.NewTicker(1 * time.Second) 36 defer ticker.Stop() 37 for { 38 select { 39 case <-ticker.C: 40 now := time.Now() 41 nowStr := now.Format("15 04") 42 parts := strings.Split(nowStr, " ") 43 44 spacer := " " 45 if now.Second()%2 == 0 { 46 spacer = ":" 47 } 48 chunks := []*segmentdisplay.TextChunk{ 49 segmentdisplay.NewChunk(parts[0], segmentdisplay.WriteCellOpts(cell.FgColor(cell.ColorNumber(33)))), 50 segmentdisplay.NewChunk(spacer), 51 segmentdisplay.NewChunk(parts[1], segmentdisplay.WriteCellOpts(cell.FgColor(cell.ColorRed))), 52 } 53 if err := sd.Write(chunks); err != nil { 54 panic(err) 55 } 56 57 case <-ctx.Done(): 58 return 59 } 60 } 61} 62 63// rotate returns a new slice with inputs rotated by step. 64// I.e. for a step of one: 65// inputs[0] -> inputs[len(inputs)-1] 66// inputs[1] -> inputs[0] 67// And so on. 68func rotate(inputs []rune, step int) []rune { 69 return append(inputs[step:], inputs[:step]...) 70} 71 72// rollText rolls a text across the segment display. 73// Exists when the context expires. 74func rollText(ctx context.Context, sd *segmentdisplay.SegmentDisplay) { 75 const text = "Termdash" 76 colors := map[rune]cell.Color{ 77 'T': cell.ColorNumber(33), 78 'e': cell.ColorRed, 79 'r': cell.ColorYellow, 80 'm': cell.ColorNumber(33), 81 'd': cell.ColorGreen, 82 'a': cell.ColorRed, 83 's': cell.ColorGreen, 84 'h': cell.ColorRed, 85 } 86 87 var state []rune 88 for i := 0; i < len(text); i++ { 89 state = append(state, ' ') 90 } 91 state = append(state, []rune(text)...) 92 ticker := time.NewTicker(1 * time.Second) 93 defer ticker.Stop() 94 for { 95 select { 96 case <-ticker.C: 97 var chunks []*segmentdisplay.TextChunk 98 for i := 0; i < len(text); i++ { 99 chunks = append(chunks, segmentdisplay.NewChunk( 100 string(state[i]), 101 segmentdisplay.WriteCellOpts(cell.FgColor(colors[state[i]])), 102 )) 103 } 104 if err := sd.Write(chunks); err != nil { 105 panic(err) 106 } 107 state = rotate(state, 1) 108 109 case <-ctx.Done(): 110 return 111 } 112 } 113} 114 115func main() { 116 t, err := tcell.New() 117 if err != nil { 118 panic(err) 119 } 120 defer t.Close() 121 122 ctx, cancel := context.WithCancel(context.Background()) 123 clockSD, err := segmentdisplay.New() 124 if err != nil { 125 panic(err) 126 } 127 go clock(ctx, clockSD) 128 129 rollingSD, err := segmentdisplay.New() 130 if err != nil { 131 panic(err) 132 } 133 go rollText(ctx, rollingSD) 134 135 c, err := container.New( 136 t, 137 container.Border(linestyle.Light), 138 container.BorderTitle("PRESS Q TO QUIT"), 139 container.SplitHorizontal( 140 container.Top( 141 container.PlaceWidget(rollingSD), 142 ), 143 container.Bottom( 144 container.PlaceWidget(clockSD), 145 ), 146 container.SplitPercent(40), 147 ), 148 ) 149 if err != nil { 150 panic(err) 151 } 152 153 quitter := func(k *terminalapi.Keyboard) { 154 if k.Key == 'q' || k.Key == 'Q' { 155 cancel() 156 } 157 } 158 159 if err := termdash.Run(ctx, t, c, termdash.KeyboardSubscriber(quitter), termdash.RedrawInterval(1*time.Second)); err != nil { 160 panic(err) 161 } 162} 163