github.com/loomnetwork/gamechain@v0.0.0-20200406110549-36c47eb97a92/tools/cmd/console_game/gui.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "log" 6 7 c "github.com/jroimartin/gocui" 8 "github.com/pkg/errors" 9 ) 10 11 const ( 12 // List box width. 13 lw = 20 14 // Input box height. 15 ih = 3 16 // Debug lines height 17 db = 4 18 ) 19 20 // Items to fill the list with. 21 var listItems = []string{ 22 "Health: 20", 23 "Cards inHand", 24 "---------", 25 "Minion", 26 "General", 27 "Bob", 28 } 29 30 func runGocui() { 31 // Create a new GUI. 32 g, err := c.NewGui(c.OutputNormal) 33 if err != nil { 34 log.Println("Failed to create a GUI:", err) 35 return 36 } 37 defer g.Close() 38 39 g.Cursor = true 40 g.SetManagerFunc(layout) 41 42 err = g.SetKeybinding("", c.KeyCtrlC, c.ModNone, quit) 43 if err != nil { 44 log.Println("Could not set key binding:", err) 45 return 46 } 47 48 // Now let's define the views. 49 50 // The terminal's width and height are needed for layout calculations. 51 tw, th := g.Size() 52 53 // First, create the list view. 54 lv, err := g.SetView("player1", 0, 0, lw, (th/2)-1) 55 // ErrUnknownView is not a real error condition. 56 // It just says that the view did not exist before and needs initialization. 57 if err != nil && err != c.ErrUnknownView { 58 log.Println("Failed to create main view:", err) 59 return 60 } 61 lv.Title = "Player1" 62 lv.FgColor = c.ColorCyan 63 64 // First, create the player2 list view. 65 lv2, err := g.SetView("player2", 0, (th / 2), lw, th-1) 66 // ErrUnknownView is not a real error condition. 67 // It just says that the view did not exist before and needs initialization. 68 if err != nil && err != c.ErrUnknownView { 69 log.Println("Failed to create main view:", err) 70 return 71 } 72 lv2.Title = "Player2" 73 lv2.FgColor = c.ColorGreen 74 75 //---------------board 76 // Then the output view. 77 ov, err := g.SetView("board", lw+1, 0, tw-1, th-db-ih-1) 78 if err != nil && err != c.ErrUnknownView { 79 log.Println("Failed to create board view:", err) 80 return 81 } 82 ov.Title = "ZombieBattleground - Console edition - Play Board" 83 ov.FgColor = c.ColorGreen 84 // Let the view scroll if the output exceeds the visible area. 85 ov.Autoscroll = true 86 87 // Then the output view. 88 bp1, err := g.SetView("board-player1", lw+2, 1, tw-3, th-db-ih-4) 89 if err != nil && err != c.ErrUnknownView { 90 log.Println("Failed to create board view:", err) 91 return 92 } 93 bp1.Title = "Player 1 - Board" 94 bp1.FgColor = c.ColorGreen 95 // Let the view scroll if the output exceeds the visible area. 96 bp1.Autoscroll = true 97 _, err = fmt.Fprintln(bp1, "Cards on Table\n General #1 \n General #2, Minion") 98 check(err) 99 100 player1Height := th - db - ih - 3 101 bp2, err := g.SetView("board-player2", lw+2, player1Height/2, tw-3, th-db-ih-2) 102 if err != nil && err != c.ErrUnknownView { 103 log.Println("Failed to create board view:", err) 104 return 105 } 106 bp2.Title = "Player 2 - Board" 107 bp2.FgColor = c.ColorRed 108 // Let the view scroll if the output exceeds the visible area. 109 bp2.Autoscroll = true 110 _, err = fmt.Fprintln(bp2, "Cards on Table\n General #1 \n General #2, Minion") 111 check(err) 112 113 ///------------end board 114 115 db, err := g.SetView("Debug Logs", lw+1, th-db-ih-1, tw-1, th-1) 116 if err != nil && err != c.ErrUnknownView { 117 log.Println("Failed to create board view:", err) 118 return 119 } 120 db.Title = "Debug Logs" 121 db.FgColor = c.ColorGreen 122 // Let the view scroll if the output exceeds the visible area. 123 db.Autoscroll = true 124 _, err = fmt.Fprintln(db, "Incoming Transactions ....") 125 if err != nil { 126 log.Println("Failed to print into output view:", err) 127 } 128 _, err = fmt.Fprintln(db, "Press Ctrl-c to quit") 129 if err != nil { 130 log.Println("Failed to print into output view:", err) 131 } 132 133 // And finally the input view. 134 iv, err := g.SetView("input", lw+1, th-ih, tw-1, th-1) 135 if err != nil && err != c.ErrUnknownView { 136 log.Println("Failed to create input view:", err) 137 return 138 } 139 iv.Title = "Input" 140 iv.FgColor = c.ColorYellow 141 // The input view shall be editable. 142 iv.Editable = true 143 err = iv.SetCursor(0, 0) 144 if err != nil { 145 log.Println("Failed to set cursor:", err) 146 return 147 } 148 149 // Make the enter key copy the input to the output. 150 err = g.SetKeybinding("input", c.KeyEnter, c.ModNone, func(g *c.Gui, iv *c.View) error { 151 // We want to read the view's buffer from the beginning. 152 iv.Rewind() 153 154 // Get the output view via its name. 155 ov, e := g.View("board") 156 if e != nil { 157 log.Println("Cannot get board view:", e) 158 return e 159 } 160 // Thanks to views being an io.Writer, we can simply Fprint to a view. 161 _, e = fmt.Fprint(ov, iv.Buffer()) 162 if e != nil { 163 log.Println("Cannot print to output view:", e) 164 } 165 // Clear the input view 166 iv.Clear() 167 // Put the cursor back to the start. 168 e = iv.SetCursor(0, 0) 169 if e != nil { 170 log.Println("Failed to set cursor:", e) 171 } 172 return e 173 174 }) 175 if err != nil { 176 log.Println("Cannot bind the enter key:", err) 177 } 178 179 // Fill the list view. 180 for _, s := range listItemsForPlayer(1) { 181 // Again, we can simply Fprint to a view. 182 _, err = fmt.Fprintln(lv, s) 183 if err != nil { 184 log.Println("Error writing to the list view:", err) 185 return 186 } 187 } 188 for _, s := range listItemsForPlayer(2) { 189 _, err = fmt.Fprintln(lv2, s) 190 if err != nil { 191 log.Println("Error writing to the list view:", err) 192 return 193 } 194 } 195 196 // Set the focus to the input view. 197 _, err = g.SetCurrentView("input") 198 if err != nil { 199 log.Println("Cannot set focus to input view:", err) 200 } 201 202 // Start the main loop. 203 err = g.MainLoop() 204 log.Println("Main loop has finished:", err) 205 } 206 207 // The layout handler calculates all sizes depending 208 // on the current terminal size. 209 func layout(g *c.Gui) error { 210 // Get the current terminal size. 211 tw, th := g.Size() 212 213 // Update the views according to the new terminal size. 214 _, err := g.SetView("player1", 0, 0, lw, (th/2)-1) 215 if err != nil { 216 return errors.Wrap(err, "Cannot update player1 view") 217 } 218 _, err = g.SetView("player2", 0, (th / 2), lw, th-1) 219 if err != nil { 220 return errors.Wrap(err, "Cannot update player1 view") 221 } 222 _, err = g.SetView("board", lw+1, 0, tw-1, th-ih-1) 223 if err != nil { 224 return errors.Wrap(err, "Cannot update board view") 225 } 226 _, err = g.SetView("Debug Logs", lw+1, th-db-ih-1, tw-1, th-1) 227 if err != nil && err != c.ErrUnknownView { 228 log.Println("Failed to create board view:", err) 229 return errors.Wrap(err, "Cannot update debug view") 230 } 231 _, err = g.SetView("board-player1", lw+2, 1, tw-3, th-db-ih-4) 232 if err != nil { 233 return errors.Wrap(err, "Cannot update board view") 234 } 235 236 player1Height := th - db - ih - 3 237 _, err = g.SetView("board-player2", lw+2, player1Height/2, tw-3, th-db-ih-2) 238 if err != nil { 239 return errors.Wrap(err, "Cannot update board view") 240 } 241 _, err = g.SetView("input", lw+1, th-ih, tw-1, th-1) 242 if err != nil { 243 return errors.Wrap(err, "Cannot update input view.") 244 } 245 return nil 246 } 247 248 // `quit` is a handler that gets bound to Ctrl-C. 249 // It signals the main loop to exit. 250 func quit(g *c.Gui, v *c.View) error { 251 return c.ErrQuit 252 } 253 254 /* 255 Our main func just needs to read the name from the TUI lib from the command line 256 and execute the respective code. 257 */ 258 259 // would never use this in a serious program 260 func check(err error) { 261 if err != nil { 262 panic(err) 263 } 264 }