forked from jroimartin/gocui
-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into fix-text-insert
Showing
19 changed files
with
1,144 additions
and
215 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
*.swp | ||
.idea | ||
.vscode |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
|
||
"github.com/awesome-gocui/gocui" | ||
) | ||
|
||
var ( | ||
viewArr = []string{"v1", "v2", "v3", "v4"} | ||
active = 0 | ||
) | ||
|
||
func setCurrentViewOnTop(g *gocui.Gui, name string) (*gocui.View, error) { | ||
if _, err := g.SetCurrentView(name); err != nil { | ||
return nil, err | ||
} | ||
return g.SetViewOnTop(name) | ||
} | ||
|
||
func nextView(g *gocui.Gui, v *gocui.View) error { | ||
nextIndex := (active + 1) % len(viewArr) | ||
name := viewArr[nextIndex] | ||
|
||
out, err := g.View("v1") | ||
if err != nil { | ||
return err | ||
} | ||
fmt.Fprintln(out, "Going from view "+v.Name()+" to "+name) | ||
|
||
if _, err := setCurrentViewOnTop(g, name); err != nil { | ||
return err | ||
} | ||
|
||
if nextIndex == 3 { | ||
g.Cursor = true | ||
} else { | ||
g.Cursor = false | ||
} | ||
|
||
active = nextIndex | ||
return nil | ||
} | ||
|
||
func layout(g *gocui.Gui) error { | ||
maxX, maxY := g.Size() | ||
if v, err := g.SetView("v1", 0, 0, maxX/2-1, maxY/2-1, gocui.RIGHT); err != nil { | ||
if !gocui.IsUnknownView(err) { | ||
return err | ||
} | ||
v.Title = "v1" | ||
v.Autoscroll = true | ||
fmt.Fprintln(v, "View with default frame color") | ||
fmt.Fprintln(v, "It's connected to v2 with overlay RIGHT.\n") | ||
if _, err = setCurrentViewOnTop(g, "v1"); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
if v, err := g.SetView("v2", maxX/2-1, 0, maxX-1, maxY/2-1, gocui.LEFT); err != nil { | ||
if !gocui.IsUnknownView(err) { | ||
return err | ||
} | ||
v.Title = "v2" | ||
v.Wrap = true | ||
v.FrameColor = gocui.ColorMagenta | ||
v.FrameRunes = []rune{'═', '│'} | ||
fmt.Fprintln(v, "View with minimum frame customization and colored frame.") | ||
fmt.Fprintln(v, "It's connected to v1 with overlay LEFT.\n") | ||
fmt.Fprintln(v, "\033[35;1mInstructions:\033[0m") | ||
fmt.Fprintln(v, "Press TAB to change current view") | ||
fmt.Fprintln(v, "Press Ctrl+O to toggle gocui.SupportOverlap\n") | ||
fmt.Fprintln(v, "\033[32;2mSelected frame is highlighted with green color\033[0m") | ||
} | ||
if v, err := g.SetView("v3", 0, maxY/2, maxX/2-1, maxY-1, 0); err != nil { | ||
if !gocui.IsUnknownView(err) { | ||
return err | ||
} | ||
v.Title = "v3" | ||
v.Wrap = true | ||
v.Autoscroll = true | ||
v.FrameColor = gocui.ColorCyan | ||
v.TitleColor = gocui.ColorCyan | ||
v.FrameRunes = []rune{'═', '║', '╔', '╗', '╚', '╝'} | ||
fmt.Fprintln(v, "View with basic frame customization and colored frame and title") | ||
fmt.Fprintln(v, "It's not connected to any view.") | ||
} | ||
if v, err := g.SetView("v4", maxX/2, maxY/2, maxX-1, maxY-1, gocui.LEFT); err != nil { | ||
if !gocui.IsUnknownView(err) { | ||
return err | ||
} | ||
v.Title = "v4" | ||
v.Subtitle = "(editable)" | ||
v.Editable = true | ||
v.TitleColor = gocui.ColorYellow | ||
v.FrameColor = gocui.ColorRed | ||
v.FrameRunes = []rune{'═', '║', '╔', '╗', '╚', '╝', '╠', '╣', '╦', '╩', '╬'} | ||
fmt.Fprintln(v, "View with fully customized frame and colored title differently.") | ||
fmt.Fprintln(v, "It's connected to v3 with overlay LEFT.\n") | ||
v.SetCursor(0, 3) | ||
} | ||
return nil | ||
} | ||
|
||
func quit(g *gocui.Gui, v *gocui.View) error { | ||
return gocui.ErrQuit | ||
} | ||
|
||
func toggleOverlap(g *gocui.Gui, v *gocui.View) error { | ||
g.SupportOverlaps = !g.SupportOverlaps | ||
return nil | ||
} | ||
|
||
func main() { | ||
g, err := gocui.NewGui(gocui.OutputNormal, true) | ||
if err != nil { | ||
log.Panicln(err) | ||
} | ||
defer g.Close() | ||
|
||
g.Highlight = true | ||
g.SelFgColor = gocui.ColorGreen | ||
g.SelFrameColor = gocui.ColorGreen | ||
|
||
g.SetManagerFunc(layout) | ||
|
||
if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { | ||
log.Panicln(err) | ||
} | ||
if err := g.SetKeybinding("", gocui.KeyCtrlO, gocui.ModNone, toggleOverlap); err != nil { | ||
log.Panicln(err) | ||
} | ||
if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, nextView); err != nil { | ||
log.Panicln(err) | ||
} | ||
|
||
if err := g.MainLoop(); err != nil && !gocui.IsQuit(err) { | ||
log.Panicln(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,165 @@ | ||
// Copyright 2014 The gocui Authors. All rights reserved. | ||
// Copyright 2020 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 gocui | ||
|
||
import "github.com/awesome-gocui/termbox-go" | ||
import "github.com/gdamore/tcell/v2" | ||
|
||
// Attribute represents a terminal attribute, like color, font style, etc. They | ||
// can be combined using bitwise OR (|). Note that it is not possible to | ||
// combine multiple color attributes. | ||
type Attribute termbox.Attribute | ||
// Attribute affects the presentation of characters, such as color, boldness, etc. | ||
type Attribute uint64 | ||
|
||
// Color attributes. | ||
const ( | ||
ColorDefault Attribute = Attribute(termbox.ColorDefault) | ||
ColorBlack = Attribute(termbox.ColorBlack) | ||
ColorRed = Attribute(termbox.ColorRed) | ||
ColorGreen = Attribute(termbox.ColorGreen) | ||
ColorYellow = Attribute(termbox.ColorYellow) | ||
ColorBlue = Attribute(termbox.ColorBlue) | ||
ColorMagenta = Attribute(termbox.ColorMagenta) | ||
ColorCyan = Attribute(termbox.ColorCyan) | ||
ColorWhite = Attribute(termbox.ColorWhite) | ||
// ColorDefault is used to leave the Color unchanged from whatever system or teminal default may exist. | ||
ColorDefault = Attribute(tcell.ColorDefault) | ||
|
||
// AttrIsValidColor is used to indicate the color value is actually | ||
// valid (initialized). This is useful to permit the zero value | ||
// to be treated as the default. | ||
AttrIsValidColor = Attribute(tcell.ColorValid) | ||
|
||
// AttrIsRGBColor is used to indicate that the Attribute value is RGB value of color. | ||
// The lower order 3 bytes are RGB. | ||
// (It's not a color in basic ANSI range 256). | ||
AttrIsRGBColor = Attribute(tcell.ColorIsRGB) | ||
|
||
// AttrColorBits is a mask where color is located in Attribute | ||
AttrColorBits = 0xffffffffff // roughly 5 bytes, tcell uses 4 bytes and half-byte as a special flags for color (rest is reserved for future) | ||
|
||
// AttrStyleBits is a mask where character attributes (e.g.: bold, italic, underline) are located in Attribute | ||
AttrStyleBits = 0xffffff0000000000 // remaining 3 bytes in the 8 bytes Attribute (tcell is not using it, so we should be fine) | ||
) | ||
|
||
// Color attributes. These colors are compatible with tcell.Color type and can be expanded like: | ||
// g.FgColor := gocui.Attribute(tcell.ColorLime) | ||
const ( | ||
ColorBlack Attribute = AttrIsValidColor + iota | ||
ColorRed | ||
ColorGreen | ||
ColorYellow | ||
ColorBlue | ||
ColorMagenta | ||
ColorCyan | ||
ColorWhite | ||
) | ||
|
||
// Text style attributes. | ||
// grayscale indexes (for backward compatibility with termbox-go original grayscale) | ||
var grayscale = []tcell.Color{ | ||
16, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, | ||
245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 231, | ||
} | ||
|
||
// Attributes are not colors, but effects (e.g.: bold, dim) which affect the display of text. | ||
// They can be combined. | ||
const ( | ||
AttrBold Attribute = Attribute(termbox.AttrBold) | ||
AttrUnderline = Attribute(termbox.AttrUnderline) | ||
AttrReverse = Attribute(termbox.AttrReverse) | ||
AttrBold Attribute = 1 << (40 + iota) | ||
AttrBlink | ||
AttrReverse | ||
AttrUnderline | ||
AttrDim | ||
AttrItalic | ||
AttrStrikeThrough | ||
AttrNone Attribute = 0 // Just normal text. | ||
) | ||
|
||
// AttrAll represents all the text effect attributes turned on | ||
const AttrAll = AttrBold | AttrBlink | AttrReverse | AttrUnderline | AttrDim | AttrItalic | ||
|
||
// IsValidColor indicates if the Attribute is a valid color value (has been set). | ||
func (a Attribute) IsValidColor() bool { | ||
return a&AttrIsValidColor != 0 | ||
} | ||
|
||
// Hex returns the color's hexadecimal RGB 24-bit value with each component | ||
// consisting of a single byte, ala R << 16 | G << 8 | B. If the color | ||
// is unknown or unset, -1 is returned. | ||
// | ||
// This function produce the same output as `tcell.Hex()` with additional | ||
// support for `termbox-go` colors (to 256). | ||
func (a Attribute) Hex() int32 { | ||
if !a.IsValidColor() { | ||
return -1 | ||
} | ||
tc := getTcellColor(a, OutputTrue) | ||
return tc.Hex() | ||
} | ||
|
||
// RGB returns the red, green, and blue components of the color, with | ||
// each component represented as a value 0-255. If the color | ||
// is unknown or unset, -1 is returned for each component. | ||
// | ||
// This function produce the same output as `tcell.RGB()` with additional | ||
// support for `termbox-go` colors (to 256). | ||
func (a Attribute) RGB() (int32, int32, int32) { | ||
v := a.Hex() | ||
if v < 0 { | ||
return -1, -1, -1 | ||
} | ||
return (v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff | ||
} | ||
|
||
// GetColor creates a Color from a color name (W3C name). A hex value may | ||
// be supplied as a string in the format "#ffffff". | ||
func GetColor(color string) Attribute { | ||
return Attribute(tcell.GetColor(color)) | ||
} | ||
|
||
// Get256Color creates Attribute which stores ANSI color (0-255) | ||
func Get256Color(color int32) Attribute { | ||
return Attribute(color) | AttrIsValidColor | ||
} | ||
|
||
// GetRGBColor creates Attribute which stores RGB color. | ||
// Color is passed as 24bit RGB value, where R << 16 | G << 8 | B | ||
func GetRGBColor(color int32) Attribute { | ||
return Attribute(color) | AttrIsValidColor | AttrIsRGBColor | ||
} | ||
|
||
// NewRGBColor creates Attribute which stores RGB color. | ||
func NewRGBColor(r, g, b int32) Attribute { | ||
return Attribute(tcell.NewRGBColor(r, g, b)) | ||
} | ||
|
||
// getTcellColor transform Attribute into tcell.Color | ||
func getTcellColor(c Attribute, omode OutputMode) tcell.Color { | ||
c = c & AttrColorBits | ||
// Default color is 0 in tcell/v2 and was 0 in termbox-go, so we are good here | ||
if c == ColorDefault { | ||
return tcell.ColorDefault | ||
} | ||
|
||
tc := tcell.ColorDefault | ||
// Check if we have valid color | ||
if c.IsValidColor() { | ||
tc = tcell.Color(c) | ||
} else if c > 0 && c <= 256 { | ||
// It's not valid color, but it has value in range 1-256 | ||
// This is old Attribute style of color from termbox-go (black=1, etc.) | ||
// convert to tcell color (black=0|ColorValid) | ||
tc = tcell.Color(c-1) | tcell.ColorValid | ||
} | ||
|
||
switch omode { | ||
case OutputTrue: | ||
return tc | ||
case OutputNormal: | ||
tc &= tcell.Color(0xf) | tcell.ColorValid | ||
case Output256: | ||
tc &= tcell.Color(0xff) | tcell.ColorValid | ||
case Output216: | ||
tc &= tcell.Color(0xff) | ||
if tc > 215 { | ||
return tcell.ColorDefault | ||
} | ||
tc += tcell.Color(16) | tcell.ColorValid | ||
case OutputGrayscale: | ||
tc &= tcell.Color(0x1f) | ||
if tc > 26 { | ||
return tcell.ColorDefault | ||
} | ||
tc = grayscale[tc] | tcell.ColorValid | ||
default: | ||
return tcell.ColorDefault | ||
} | ||
return tc | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,15 @@ | ||
github.com/awesome-gocui/termbox-go v0.0.0-20190427202837-c0aef3d18bcc h1:wGNpKcHU8Aadr9yOzsT3GEsFLS7HQu8HxQIomnekqf0= | ||
github.com/awesome-gocui/termbox-go v0.0.0-20190427202837-c0aef3d18bcc/go.mod h1:tOy3o5Nf1bA17mnK4W41gD7PS3u4Cv0P0pqFcoWMy8s= | ||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= | ||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= | ||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= | ||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= | ||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= | ||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= | ||
github.com/gdamore/tcell/v2 v2.0.0 h1:GRWG8aLfWAlekj9Q6W29bVvkHENc6hp79XOqG4AWDOs= | ||
github.com/gdamore/tcell/v2 v2.0.0/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA= | ||
github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4= | ||
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= | ||
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= | ||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= | ||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= | ||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= | ||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= | ||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756 h1:9nuHUbU8dRnRRfj9KjWUVrJeoexdbeMjttk6Oh1rD10= | ||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,205 @@ | ||
// Copyright 2020 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 gocui | ||
|
||
import ( | ||
"github.com/gdamore/tcell/v2" | ||
) | ||
|
||
var screen tcell.Screen | ||
|
||
// tcellInit initializes tcell screen for use. | ||
func tcellInit() error { | ||
if s, e := tcell.NewScreen(); e != nil { | ||
return e | ||
} else if e = s.Init(); e != nil { | ||
return e | ||
} else { | ||
screen = s | ||
return nil | ||
} | ||
} | ||
|
||
// tcellSetCell sets the character cell at a given location to the given | ||
// content (rune) and attributes using provided OutputMode | ||
func tcellSetCell(x, y int, ch rune, fg, bg Attribute, omode OutputMode) { | ||
st := getTcellStyle(fg, bg, omode) | ||
screen.SetContent(x, y, ch, nil, st) | ||
} | ||
|
||
// getTcellStyle creates tcell.Style from Attributes | ||
func getTcellStyle(fg, bg Attribute, omode OutputMode) tcell.Style { | ||
st := tcell.StyleDefault | ||
|
||
// extract colors and attributes | ||
if fg != ColorDefault { | ||
st = st.Foreground(getTcellColor(fg, omode)) | ||
st = setTcellFontEffectStyle(st, fg) | ||
} | ||
if bg != ColorDefault { | ||
st = st.Background(getTcellColor(bg, omode)) | ||
st = setTcellFontEffectStyle(st, bg) | ||
} | ||
|
||
return st | ||
} | ||
|
||
// setTcellFontEffectStyle add additional attributes to tcell.Style | ||
func setTcellFontEffectStyle(st tcell.Style, attr Attribute) tcell.Style { | ||
if attr&AttrBold != 0 { | ||
st = st.Bold(true) | ||
} | ||
if attr&AttrUnderline != 0 { | ||
st = st.Underline(true) | ||
} | ||
if attr&AttrReverse != 0 { | ||
st = st.Reverse(true) | ||
} | ||
if attr&AttrBlink != 0 { | ||
st = st.Blink(true) | ||
} | ||
if attr&AttrDim != 0 { | ||
st = st.Dim(true) | ||
} | ||
if attr&AttrItalic != 0 { | ||
st = st.Italic(true) | ||
} | ||
if attr&AttrStrikeThrough != 0 { | ||
st = st.StrikeThrough(true) | ||
} | ||
return st | ||
} | ||
|
||
// gocuiEventType represents the type of event. | ||
type gocuiEventType uint8 | ||
|
||
// gocuiEvent represents events like a keys, mouse actions, or window resize. | ||
// The 'Mod', 'Key' and 'Ch' fields are valid if 'Type' is 'eventKey'. | ||
// The 'MouseX' and 'MouseY' fields are valid if 'Type' is 'eventMouse'. | ||
// The 'Width' and 'Height' fields are valid if 'Type' is 'eventResize'. | ||
// The 'Err' field is valid if 'Type' is 'eventError'. | ||
type gocuiEvent struct { | ||
Type gocuiEventType | ||
Mod Modifier | ||
Key Key | ||
Ch rune | ||
Width int | ||
Height int | ||
Err error | ||
MouseX int | ||
MouseY int | ||
N int | ||
} | ||
|
||
// Event types. | ||
const ( | ||
eventNone gocuiEventType = iota | ||
eventKey | ||
eventResize | ||
eventMouse | ||
eventInterrupt | ||
eventError | ||
eventRaw | ||
) | ||
|
||
var ( | ||
lastMouseKey tcell.ButtonMask = tcell.ButtonNone | ||
lastMouseMod tcell.ModMask = tcell.ModNone | ||
) | ||
|
||
// pollEvent get tcell.Event and transform it into gocuiEvent | ||
func pollEvent() gocuiEvent { | ||
tev := screen.PollEvent() | ||
switch tev := tev.(type) { | ||
case *tcell.EventInterrupt: | ||
return gocuiEvent{Type: eventInterrupt} | ||
case *tcell.EventResize: | ||
w, h := tev.Size() | ||
return gocuiEvent{Type: eventResize, Width: w, Height: h} | ||
case *tcell.EventKey: | ||
k := tev.Key() | ||
ch := rune(0) | ||
if k == tcell.KeyRune { | ||
k = 0 // if rune remove key (so it can match rune instead of key) | ||
ch = tev.Rune() | ||
if ch == ' ' { | ||
// special handling for spacebar | ||
k = 32 // tcell keys ends at 31 or starts at 256 | ||
ch = rune(0) | ||
} | ||
} | ||
mod := tev.Modifiers() | ||
// remove control modifier and setup special handling of ctrl+spacebar, etc. | ||
if mod == tcell.ModCtrl && k == 32 { | ||
mod = 0 | ||
ch = rune(0) | ||
k = tcell.KeyCtrlSpace | ||
} else if mod == tcell.ModCtrl || mod == tcell.ModShift { | ||
// remove Ctrl or Shift if specified | ||
// - shift - will be translated to the final code of rune | ||
// - ctrl - is translated in the key | ||
mod = 0 | ||
} | ||
return gocuiEvent{ | ||
Type: eventKey, | ||
Key: Key(k), | ||
Ch: ch, | ||
Mod: Modifier(mod), | ||
} | ||
case *tcell.EventMouse: | ||
x, y := tev.Position() | ||
button := tev.Buttons() | ||
mouseKey := MouseRelease | ||
mouseMod := ModNone | ||
// process mouse wheel | ||
if button&tcell.WheelUp != 0 { | ||
mouseKey = MouseWheelUp | ||
} | ||
if button&tcell.WheelDown != 0 { | ||
mouseKey = MouseWheelDown | ||
} | ||
if button&tcell.WheelLeft != 0 { | ||
mouseKey = MouseWheelLeft | ||
} | ||
if button&tcell.WheelRight != 0 { | ||
mouseKey = MouseWheelRight | ||
} | ||
|
||
// process button events (not wheel events) | ||
button &= tcell.ButtonMask(0xff) | ||
if button != tcell.ButtonNone && lastMouseKey == tcell.ButtonNone { | ||
lastMouseKey = button | ||
lastMouseMod = tev.Modifiers() | ||
} | ||
|
||
switch tev.Buttons() { | ||
case tcell.ButtonNone: | ||
if lastMouseKey != tcell.ButtonNone { | ||
switch lastMouseKey { | ||
case tcell.ButtonPrimary: | ||
mouseKey = MouseLeft | ||
case tcell.ButtonSecondary: | ||
mouseKey = MouseRight | ||
case tcell.ButtonMiddle: | ||
mouseKey = MouseMiddle | ||
} | ||
mouseMod = Modifier(lastMouseMod) | ||
lastMouseMod = tcell.ModNone | ||
lastMouseKey = tcell.ButtonNone | ||
} | ||
} | ||
|
||
return gocuiEvent{ | ||
Type: eventMouse, | ||
MouseX: x, | ||
MouseY: y, | ||
Key: mouseKey, | ||
Ch: 0, | ||
Mod: mouseMod, | ||
} | ||
default: | ||
return gocuiEvent{Type: eventNone} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters