Skip to content

Commit

Permalink
Merge pull request #73 from dankox/feature/swap-to-tcell
Browse files Browse the repository at this point in the history
Feature/swap to tcell/v2
  • Loading branch information
mjarkk authored Dec 23, 2020
2 parents 1e2601e + d20d452 commit 0692492
Show file tree
Hide file tree
Showing 16 changed files with 821 additions and 193 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
*.swp
.idea
.vscode
56 changes: 56 additions & 0 deletions CHANGES_tcell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Change from termbox to tcell

Original GOCUI was written on top of [termbox](https://github.com/nsf/termbox-go) package. This document describes changes which were done to be able to use to [tcell/v2](https://github.com/gdamore/tcell) package.

## Attribute color

Attribute type represents a terminal attribute like color and font effects. Color and font effects can be combined using bitwise OR (`|`).

In `termbox` colors were represented by range 1 to 256. `0` was default color which uses the terminal default setting.

In `tcell` colors can be represented in 24bit, and all of them starts from 0. Valid colors have special flag which gives them real value starting from 4294967296. `0` is a default similart to `termbox`.
The change to support all these colors was made in a way, that original colors from 1 to 256 are backward compatible and if user has color specified as
`Attribute(ansicolor+1)` without the valid color flag, it will be translated to `tcell` color by subtracting 1 and making the color valid by adding the flag. This should ensure backward compatibility.

All the color constants are the same with different underlying values. From user perspective, this should be fine unless some arithmetic is done with it. For example `ColorBlack` was `1` in original version but is `4294967296` in new version.

GOCUI provides a few helper functions which could be used to get the real color value or to create a color attribute.

- `(a Attribute).Hex()` - returns `int32` value of the color represented as `Red << 16 | Green << 8 | Blue`
- `(a Attribute).RGB()` - returns 3 `int32` values for red, green and blue color.
- `GetColor(string)` - creates `Attribute` from color passed as a string. This can be hex value or color name (W3C name).
- `Get256Color(int32)` - creates `Attribute` from color number (ANSI colors).
- `GetRGBColor(int32)` - creates `Attribute` from color number created the same way as `Hex()` function returns.
- `NewRGBColor(int32, int32, int32)` - creates `Attribute` from color numbers for red, green and blue values.

## Attribute font effect

There were 3 attributes for font effect, `AttrBold`, `AttrUnderline` and `AttrReverse`.

`tcell` supports more attributes, so they were added. All of these attributes have different values from before. However they can be used in the same way as before.

All the font effect attributes:
- `AttrBold`
- `AttrBlink`
- `AttrReverse`
- `AttrUnderline`
- `AttrDim`
- `AttrItalic`
- `AttrStrikeThrough`

## OutputMode

`OutputMode` in `termbox` was used to translate colors into the correct range. So for example in `OutputGrayscale` you had colors from 1 - 24 all representing gray colors in range 232 - 255, and white and black color.

`tcell` colors are 24bit and they are translated by the library into the color which can be read by terminal.

The original translation from `termbox` was included in GOCUI to be backward compatible. This is enabled in all the original modes: `OutputNormal`, `Output216`, `OutputGrayscale` and `Output256`.

`OutputTrue` is a new mode. It is recomended, because in this mode GOCUI doesn't do any kind of translation of the colors and pass them directly to `tcell`. If user wants to use true color in terminal and this mode doesn't work, it might be because of the terminal setup. `tcell` has a documentation what needs to be done, but in short `COLORTERM=truecolor` environment variable should help (see [_examples/colorstrue.go](./_examples/colorstrue.go)). Other way would be to have `TERM` environment variable having value with suffix `-truecolor`. To disable true color set `TCELL_TRUECOLOR=disable`.

## Keybinding

`termbox` had different way of handling input from terminal than `tcell`. This leads to some adjustement on how the keys are represented.
In general, all the keys in GOCUI should be presented from before, but the underlying values might be different. This could lead to some problems if a user uses different parser to create the `Key` for the keybinding. If using GOCUI parser, everything should be ok.

Mouse is handled differently in `tcell`, but translation was done to keep it in the same way as it was before. However this was harder to test due to different behaviour across the platforms, so if anything is missing or not working, please report.
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![GoDoc](https://godoc.org/github.com/awesome-gocui/gocui?status.svg)](https://godoc.org/github.com/awesome-gocui/gocui)
![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/awesome-gocui/gocui.svg)

Minimalist Go package aimed at creating Console User Interfaces.
Minimalist Go package aimed at creating Console User Interfaces.
A community fork based on the amazing work of [jroimartin](https://github.com/jroimartin/gocui)

## Features
Expand All @@ -23,8 +23,9 @@ A community fork based on the amazing work of [jroimartin](https://github.com/jr

## About fork

This fork has many improvements over the original work from [jroimartin](https://github.com/jroimartin/gocui).
This fork has many improvements over the original work from [jroimartin](https://github.com/jroimartin/gocui).

* Written ontop of TCell
* Better wide character support
* Support for 1 Line height views
* Better support for running in docker container
Expand Down Expand Up @@ -68,7 +69,7 @@ import (
)

func main() {
g, err := gocui.NewGui(gocui.OutputNormal, false)
g, err := gocui.NewGui(gocui.OutputNormal, true)
if err != nil {
log.Panicln(err)
}
Expand All @@ -91,11 +92,14 @@ func layout(g *gocui.Gui) error {
if !gocui.IsUnknownView(err) {
return err
}
fmt.Fprintln(v, "Hello world!")

if _, err := g.SetCurrentView("hello"); err != nil {
return err
}

fmt.Fprintln(v, "Hello world!")
}

return nil
}

Expand Down
109 changes: 109 additions & 0 deletions _examples/colorstrue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright 2014 The gocui Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
"fmt"
"log"
"os"

"github.com/awesome-gocui/gocui"
colorful "github.com/lucasb-eyer/go-colorful"
)

var dark = false

func main() {
os.Setenv("COLORTERM", "truecolor")
g, err := gocui.NewGui(gocui.OutputTrue, true)

if err != nil {
log.Panicln(err)
}
defer g.Close()

g.SetManagerFunc(layout)

if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
log.Panicln(err)
}

if err := g.SetKeybinding("", gocui.KeyCtrlR, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error {
if dark {
dark = false
} else {
dark = true
}
displayHsv(v)

return nil
}); err != nil {
log.Panicln(err)
}

if err := g.MainLoop(); err != nil && !gocui.IsQuit(err) {
log.Panicln(err)
}
}

func layout(g *gocui.Gui) error {
maxX, maxY := g.Size()
rows := 33
cols := 182
if maxY < rows {
rows = maxY
}
if maxX < cols {
cols = maxX
}

if v, err := g.SetView("colors", 0, 0, cols-1, rows-1, 0); err != nil {
if !gocui.IsUnknownView(err) {
return err
}

v.FrameColor = gocui.GetColor("#FFAA55")
displayHsv(v)

if _, err := g.SetCurrentView("colors"); err != nil {
return err
}
}
return nil
}

func displayHsv(v *gocui.View) {
v.Clear()
str := ""
// HSV color space (lines are value or saturation)
for i := 50; i > 0; i -= 2 {
// Hue
for j := 0; j < 360; j += 2 {
ir, ig, ib := hsv(j, i-1)
ir2, ig2, ib2 := hsv(j, i)
str += fmt.Sprintf("\x1b[48;2;%d;%d;%dm\x1b[38;2;%d;%d;%dm▀\x1b[0m", ir, ig, ib, ir2, ig2, ib2)
}
str += "\n"
fmt.Fprint(v, str)
str = ""
}

fmt.Fprintln(v, "\n\x1b[38;5;245mCtrl + R - Switch light/dark mode")
fmt.Fprintln(v, "\nCtrl + C - Exit\n")
fmt.Fprint(v, "Example should enable true color, but if it doesn't work run this command: \x1b[0mexport COLORTERM=truecolor")
}

func hsv(hue, sv int) (uint32, uint32, uint32) {
if !dark {
ir, ig, ib, _ := colorful.Hsv(float64(hue), float64(sv)/50, float64(1)).RGBA()
return ir >> 8, ig >> 8, ib >> 8
}
ir, ig, ib, _ := colorful.Hsv(float64(hue), float64(1), float64(sv)/50).RGBA()
return ir >> 8, ig >> 8, ib >> 8
}

func quit(g *gocui.Gui, v *gocui.View) error {
return gocui.ErrQuit
}
1 change: 1 addition & 0 deletions _examples/dynamic.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func main() {

g.Highlight = true
g.SelFgColor = gocui.ColorRed
g.SelFrameColor = gocui.ColorRed

g.SetManagerFunc(layout)

Expand Down
2 changes: 1 addition & 1 deletion _examples/hello.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func main() {
}

if err := g.MainLoop(); err != nil && !gocui.IsQuit(err) {
log.Panicln(err.Error())
log.Panicln(err)
}
}

Expand Down
11 changes: 8 additions & 3 deletions _examples/mouse.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ func keybindings(g *gocui.Gui) error {
if err := g.SetKeybinding("msg", gocui.MouseLeft, gocui.ModNone, delMsg); err != nil {
return err
}
if err := g.SetKeybinding("", gocui.MouseRight, gocui.ModNone, delMsg); err != nil {
return err
}
if err := g.SetKeybinding("", gocui.MouseMiddle, gocui.ModNone, delMsg); err != nil {
return err
}
return nil
}

Expand Down Expand Up @@ -103,8 +109,7 @@ func showMsg(g *gocui.Gui, v *gocui.View) error {
}

func delMsg(g *gocui.Gui, v *gocui.View) error {
if err := g.DeleteView("msg"); err != nil {
return err
}
// Error check removed, because delete could be called multiple times with the above keybindings
g.DeleteView("msg")
return nil
}
2 changes: 1 addition & 1 deletion _examples/widgets.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func main() {
defer g.Close()

g.Highlight = true
g.SelFgColor = gocui.ColorRed
g.SelFrameColor = gocui.ColorRed

help := NewHelpWidget("help", 1, 1, helpText)
status := NewStatusbarWidget("status", 1, 7, 50)
Expand Down
Loading

0 comments on commit 0692492

Please sign in to comment.