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  }