mirror of
https://github.com/jroimartin/gocui.git
synced 2025-04-24 13:48:51 +08:00
Add attribute ActiveColor to configure the color of the current view
This commit is contained in:
parent
ec14132e67
commit
7779534f95
112
_examples/active.go
Normal file
112
_examples/active.go
Normal file
@ -0,0 +1,112 @@
|
||||
// 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"
|
||||
|
||||
"github.com/jroimartin/gocui"
|
||||
)
|
||||
|
||||
const LEN = 4
|
||||
|
||||
var (
|
||||
viewArr = [LEN]string{"v1", "v2", "v3", "v4"}
|
||||
active = 0
|
||||
)
|
||||
|
||||
func nextView(g *gocui.Gui, v *gocui.View) error {
|
||||
nextIndex := (active + 1) % LEN
|
||||
name := viewArr[nextIndex]
|
||||
out, _ := g.View("v2")
|
||||
fmt.Fprintln(out, "Going from view "+v.Name()+" to "+name)
|
||||
|
||||
if err := g.SetCurrentViewOnTop(name); err != nil {
|
||||
fmt.Fprintln(out, err)
|
||||
return err
|
||||
}
|
||||
|
||||
if nextIndex == 0 || 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); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
return err
|
||||
}
|
||||
v.Title = "v1 (editable)"
|
||||
v.Editable = true
|
||||
v.Wrap = true
|
||||
}
|
||||
|
||||
if v, err := g.SetView("v2", maxX/2-1, 0, maxX-1, maxY/2-1); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
return err
|
||||
}
|
||||
v.Title = "v2"
|
||||
v.Editable = false
|
||||
v.Wrap = true
|
||||
v.Autoscroll = true
|
||||
v.ActiveColor = gocui.ColorRed
|
||||
}
|
||||
if v, err := g.SetView("v3", 0, maxY/2-1, maxX/2-1, maxY-1); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
return err
|
||||
}
|
||||
v.Title = "v3"
|
||||
v.Write([]byte("Press TAB to change current view"))
|
||||
v.Wrap = true
|
||||
v.Editable = false
|
||||
v.Autoscroll = true
|
||||
v.ActiveColor = gocui.ColorRed
|
||||
}
|
||||
if v, err := g.SetView("v4", maxX/2, maxY/2, maxX-1, maxY-1); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
return err
|
||||
}
|
||||
v.Title = "v4 (editable)"
|
||||
v.Editable = true
|
||||
|
||||
if err = g.SetCurrentViewOnTop("v1"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func quit(g *gocui.Gui, v *gocui.View) error {
|
||||
return gocui.ErrQuit
|
||||
}
|
||||
|
||||
func main() {
|
||||
g := gocui.NewGui()
|
||||
if err := g.Init(); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
defer g.Close()
|
||||
|
||||
g.ActiveColor = gocui.ColorGreen
|
||||
g.SetLayout(layout)
|
||||
|
||||
if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); 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 && err != gocui.ErrQuit {
|
||||
log.Panicln(err)
|
||||
}
|
||||
}
|
82
gui.go
82
gui.go
@ -41,6 +41,9 @@ type Gui struct {
|
||||
// colors of the GUI.
|
||||
BgColor, FgColor Attribute
|
||||
|
||||
// ActiveColor allow to configure color of currentWiew frame.
|
||||
ActiveColor Attribute
|
||||
|
||||
// SelBgColor and SelFgColor are used to configure the background and
|
||||
// foreground colors of the selected line, when it is highlighted.
|
||||
SelBgColor, SelFgColor Attribute
|
||||
@ -77,6 +80,7 @@ func (g *Gui) Init() error {
|
||||
g.maxX, g.maxY = termbox.Size()
|
||||
g.BgColor = ColorBlack
|
||||
g.FgColor = ColorWhite
|
||||
g.ActiveColor = ColorWhite
|
||||
g.Editor = DefaultEditor
|
||||
return nil
|
||||
}
|
||||
@ -103,6 +107,17 @@ func (g *Gui) SetRune(x, y int, ch rune) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetRuneWithColor writes a rune at the given point, relative to the top-left
|
||||
// corner of the terminal with given colors. It checks if the position is
|
||||
// valid and applies the colors.
|
||||
func (g *Gui) SetRuneWithColor(x, y int, ch rune, fg, bg Attribute) error {
|
||||
if x < 0 || y < 0 || x >= g.maxX || y >= g.maxY {
|
||||
return errors.New("invalid point")
|
||||
}
|
||||
termbox.SetCell(x, y, ch, termbox.Attribute(fg), termbox.Attribute(bg))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Rune returns the rune contained in the cell at the given position.
|
||||
// It checks if the position is valid.
|
||||
func (g *Gui) Rune(x, y int) (rune, error) {
|
||||
@ -137,6 +152,7 @@ func (g *Gui) SetView(name string, x0, y0, x1, y1 int) (*View, error) {
|
||||
|
||||
v := newView(name, x0, y0, x1, y1)
|
||||
v.BgColor, v.FgColor = g.BgColor, g.FgColor
|
||||
v.ActiveColor = g.ActiveColor
|
||||
v.SelBgColor, v.SelFgColor = g.SelBgColor, g.SelFgColor
|
||||
g.views = append(g.views, v)
|
||||
return v, ErrUnknownView
|
||||
@ -209,6 +225,20 @@ func (g *Gui) SetCurrentView(name string) error {
|
||||
return ErrUnknownView
|
||||
}
|
||||
|
||||
// SetCurrentViewOnTop gives the focus to a given view and puts it on top
|
||||
// of existing views.
|
||||
func (g *Gui) SetCurrentViewOnTop(name string) error {
|
||||
for i, v := range g.views {
|
||||
if v.name == name {
|
||||
s := append(g.views[:i], g.views[i+1:]...)
|
||||
g.views = append(s, v)
|
||||
g.currentView = v
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return ErrUnknownView
|
||||
}
|
||||
|
||||
// CurrentView returns the currently focused view, or nil if no view
|
||||
// owns the focus.
|
||||
func (g *Gui) CurrentView() *View {
|
||||
@ -382,14 +412,21 @@ func (g *Gui) flush() error {
|
||||
}
|
||||
for _, v := range g.views {
|
||||
if v.Frame {
|
||||
if err := g.drawFrame(v); err != nil {
|
||||
// Read colors here to new variables so that frame
|
||||
// will be always drawn fully with same color
|
||||
bg := v.BgColor
|
||||
fg := v.FgColor
|
||||
if v.name == g.currentView.name {
|
||||
fg = v.ActiveColor
|
||||
}
|
||||
if err := g.drawFrame(v, fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.drawCorners(v); err != nil {
|
||||
if err := g.drawCorners(v, fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
if v.Title != "" {
|
||||
if err := g.drawTitle(v); err != nil {
|
||||
if err := g.drawTitle(v, fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -408,18 +445,18 @@ func (g *Gui) flush() error {
|
||||
}
|
||||
|
||||
// drawFrame draws the horizontal and vertical edges of a view.
|
||||
func (g *Gui) drawFrame(v *View) error {
|
||||
func (g *Gui) drawFrame(v *View, fg, bg Attribute) error {
|
||||
for x := v.x0 + 1; x < v.x1 && x < g.maxX; x++ {
|
||||
if x < 0 {
|
||||
continue
|
||||
}
|
||||
if v.y0 > -1 && v.y0 < g.maxY {
|
||||
if err := g.SetRune(x, v.y0, '─'); err != nil {
|
||||
if err := g.SetRuneWithColor(x, v.y0, '─', fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if v.y1 > -1 && v.y1 < g.maxY {
|
||||
if err := g.SetRune(x, v.y1, '─'); err != nil {
|
||||
if err := g.SetRuneWithColor(x, v.y1, '─', fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -429,12 +466,12 @@ func (g *Gui) drawFrame(v *View) error {
|
||||
continue
|
||||
}
|
||||
if v.x0 > -1 && v.x0 < g.maxX {
|
||||
if err := g.SetRune(v.x0, y, '│'); err != nil {
|
||||
if err := g.SetRuneWithColor(v.x0, y, '│', fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if v.x1 > -1 && v.x1 < g.maxX {
|
||||
if err := g.SetRune(v.x1, y, '│'); err != nil {
|
||||
if err := g.SetRuneWithColor(v.x1, y, '│', fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -443,24 +480,24 @@ func (g *Gui) drawFrame(v *View) error {
|
||||
}
|
||||
|
||||
// drawCorners draws the corners of the view.
|
||||
func (g *Gui) drawCorners(v *View) error {
|
||||
func (g *Gui) drawCorners(v *View, fg, bg Attribute) error {
|
||||
if v.x0 >= 0 && v.y0 >= 0 && v.x0 < g.maxX && v.y0 < g.maxY {
|
||||
if err := g.SetRune(v.x0, v.y0, '┌'); err != nil {
|
||||
if err := g.SetRuneWithColor(v.x0, v.y0, '┌', fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if v.x1 >= 0 && v.y0 >= 0 && v.x1 < g.maxX && v.y0 < g.maxY {
|
||||
if err := g.SetRune(v.x1, v.y0, '┐'); err != nil {
|
||||
if err := g.SetRuneWithColor(v.x1, v.y0, '┐', fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if v.x0 >= 0 && v.y1 >= 0 && v.x0 < g.maxX && v.y1 < g.maxY {
|
||||
if err := g.SetRune(v.x0, v.y1, '└'); err != nil {
|
||||
if err := g.SetRuneWithColor(v.x0, v.y1, '└', fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if v.x1 >= 0 && v.y1 >= 0 && v.x1 < g.maxX && v.y1 < g.maxY {
|
||||
if err := g.SetRune(v.x1, v.y1, '┘'); err != nil {
|
||||
if err := g.SetRuneWithColor(v.x1, v.y1, '┘', fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -468,7 +505,7 @@ func (g *Gui) drawCorners(v *View) error {
|
||||
}
|
||||
|
||||
// drawTitle draws the title of the view.
|
||||
func (g *Gui) drawTitle(v *View) error {
|
||||
func (g *Gui) drawTitle(v *View, fg, bg Attribute) error {
|
||||
if v.y0 < 0 || v.y0 >= g.maxY {
|
||||
return nil
|
||||
}
|
||||
@ -480,7 +517,7 @@ func (g *Gui) drawTitle(v *View) error {
|
||||
} else if x > v.x1-2 || x >= g.maxX {
|
||||
break
|
||||
}
|
||||
if err := g.SetRune(x, v.y0, ch); err != nil {
|
||||
if err := g.SetRuneWithColor(x, v.y0, ch, fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -526,23 +563,30 @@ func (g *Gui) draw(v *View) error {
|
||||
// of the edges that converge at these points.
|
||||
func (g *Gui) drawIntersections() error {
|
||||
for _, v := range g.views {
|
||||
// Use same active view frame coloring as tmux uses.
|
||||
// If intersection rune is part of currentView use ActiveColor.
|
||||
bg := v.BgColor
|
||||
fg := v.FgColor
|
||||
if v.name == g.currentView.name {
|
||||
fg = v.ActiveColor
|
||||
}
|
||||
if ch, ok := g.intersectionRune(v.x0, v.y0); ok {
|
||||
if err := g.SetRune(v.x0, v.y0, ch); err != nil {
|
||||
if err := g.SetRuneWithColor(v.x0, v.y0, ch, fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if ch, ok := g.intersectionRune(v.x0, v.y1); ok {
|
||||
if err := g.SetRune(v.x0, v.y1, ch); err != nil {
|
||||
if err := g.SetRuneWithColor(v.x0, v.y1, ch, fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if ch, ok := g.intersectionRune(v.x1, v.y0); ok {
|
||||
if err := g.SetRune(v.x1, v.y0, ch); err != nil {
|
||||
if err := g.SetRuneWithColor(v.x1, v.y0, ch, fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if ch, ok := g.intersectionRune(v.x1, v.y1); ok {
|
||||
if err := g.SetRune(v.x1, v.y1, ch); err != nil {
|
||||
if err := g.SetRuneWithColor(v.x1, v.y1, ch, fg, bg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
4
view.go
4
view.go
@ -29,6 +29,10 @@ type View struct {
|
||||
|
||||
ei *escapeInterpreter // used to decode ESC sequences on Write
|
||||
|
||||
// ActiveColor allow to configure the frame color of the View.
|
||||
// It will be used when focus is on view.
|
||||
ActiveColor Attribute
|
||||
|
||||
// BgColor and FgColor allow to configure the background and foreground
|
||||
// colors of the View.
|
||||
BgColor, FgColor Attribute
|
||||
|
Loading…
x
Reference in New Issue
Block a user