From 22ae449020bddd164e15d0669b2356249f894cfa Mon Sep 17 00:00:00 2001 From: Andreea Sobon Date: Mon, 4 Jan 2021 12:20:40 -0500 Subject: [PATCH] Support setting of different colors for container's border and title. --- container/container_test.go | 149 ++++++++++++++++++++++++++++++++++++ container/draw.go | 18 ++++- container/draw_test.go | 38 +++++++++ container/options.go | 23 ++++++ 4 files changed, 224 insertions(+), 4 deletions(-) diff --git a/container/container_test.go b/container/container_test.go index d4d4704..26a1917 100644 --- a/container/container_test.go +++ b/container/container_test.go @@ -1003,6 +1003,155 @@ func TestNew(t *testing.T) { return ft }, }, + { + desc: "sets border title on root container of different color", + termSize: image.Point{10, 10}, + container: func(ft *faketerm.Terminal) (*Container, error) { + return New( + ft, + Border(linestyle.Light), + BorderTitle("Ab"), + BorderColor(cell.ColorRed), + FocusedColor(cell.ColorBlue), + TitleColor(cell.ColorMagenta), + TitleFocusedColor(cell.ColorCyan), + SplitVertical( + Left( + Border(linestyle.Light), + ), + Right( + Border(linestyle.Light), + ), + ), + ) + }, + want: func(size image.Point) *faketerm.Terminal { + ft := faketerm.MustNew(size) + cvs := testcanvas.MustNew(ft.Area()) + testdraw.MustBorder( + cvs, + image.Rect(0, 0, 10, 10), + draw.BorderCellOpts(cell.FgColor(cell.ColorBlue)), + ) + testdraw.MustBorder( + cvs, + image.Rect(1, 1, 5, 9), + draw.BorderCellOpts(cell.FgColor(cell.ColorRed)), + ) + testdraw.MustBorder( + cvs, + image.Rect(5, 1, 9, 9), + draw.BorderCellOpts(cell.FgColor(cell.ColorRed)), + ) + testdraw.MustText( + cvs, + "Ab", + image.Point{1, 0}, + draw.TextCellOpts(cell.FgColor(cell.ColorCyan)), + ) + testcanvas.MustApply(cvs, ft) + return ft + }, + }, + { + desc: "sets different color title on left child container", + termSize: image.Point{10, 10}, + container: func(ft *faketerm.Terminal) (*Container, error) { + return New( + ft, + Border(linestyle.Light), + BorderColor(cell.ColorRed), + FocusedColor(cell.ColorBlue), + SplitVertical( + Left( + Border(linestyle.Light), + BorderTitle("Ab"), + TitleColor(cell.ColorMagenta), + TitleFocusedColor(cell.ColorCyan), + ), + Right( + Border(linestyle.Light), + ), + ), + ) + }, + want: func(size image.Point) *faketerm.Terminal { + ft := faketerm.MustNew(size) + cvs := testcanvas.MustNew(ft.Area()) + testdraw.MustBorder( + cvs, + image.Rect(0, 0, 10, 10), + draw.BorderCellOpts(cell.FgColor(cell.ColorBlue)), + ) + testdraw.MustBorder( + cvs, + image.Rect(1, 1, 5, 9), + draw.BorderCellOpts(cell.FgColor(cell.ColorRed)), + ) + testdraw.MustBorder( + cvs, + image.Rect(5, 1, 9, 9), + draw.BorderCellOpts(cell.FgColor(cell.ColorRed)), + ) + testdraw.MustText( + cvs, + "Ab", + image.Point{2, 1}, + draw.TextCellOpts(cell.FgColor(cell.ColorMagenta)), + ) + testcanvas.MustApply(cvs, ft) + return ft + }, + }, + + { + desc: "inherits title color on left child container", + termSize: image.Point{10, 10}, + container: func(ft *faketerm.Terminal) (*Container, error) { + return New( + ft, + Border(linestyle.Light), + BorderColor(cell.ColorRed), + FocusedColor(cell.ColorBlue), + SplitVertical( + Left( + Border(linestyle.Light), + BorderTitle("Ab"), + ), + Right( + Border(linestyle.Light), + ), + ), + ) + }, + want: func(size image.Point) *faketerm.Terminal { + ft := faketerm.MustNew(size) + cvs := testcanvas.MustNew(ft.Area()) + testdraw.MustBorder( + cvs, + image.Rect(0, 0, 10, 10), + draw.BorderCellOpts(cell.FgColor(cell.ColorBlue)), + ) + testdraw.MustBorder( + cvs, + image.Rect(1, 1, 5, 9), + draw.BorderCellOpts(cell.FgColor(cell.ColorRed)), + ) + testdraw.MustBorder( + cvs, + image.Rect(5, 1, 9, 9), + draw.BorderCellOpts(cell.FgColor(cell.ColorRed)), + ) + testdraw.MustText( + cvs, + "Ab", + image.Point{2, 1}, + draw.TextCellOpts(cell.FgColor(cell.ColorRed)), + ) + testcanvas.MustApply(cvs, ft) + return ft + }, + }, { desc: "splitting a container removes the widget", termSize: image.Point{10, 10}, diff --git a/container/draw.go b/container/draw.go index d186b12..83524b3 100644 --- a/container/draw.go +++ b/container/draw.go @@ -84,16 +84,26 @@ func drawBorder(c *Container) error { return err } - var cOpts []cell.Option + var cOpts, titleCOpts []cell.Option if c.focusTracker.isActive(c) { cOpts = append(cOpts, cell.FgColor(c.opts.inherited.focusedColor)) - } else { + if c.opts.inherited.titleFocusedColor != nil { + titleCOpts = append(titleCOpts, cell.FgColor(*c.opts.inherited.titleFocusedColor)) + } else { + titleCOpts = cOpts + } + } else { cOpts = append(cOpts, cell.FgColor(c.opts.inherited.borderColor)) - } + if c.opts.inherited.titleColor != nil { + titleCOpts = append(titleCOpts, cell.FgColor(*c.opts.inherited.titleColor)) + } else { + titleCOpts = cOpts + } + } if err := draw.Border(cvs, ar, draw.BorderLineStyle(c.opts.border), - draw.BorderTitle(c.opts.borderTitle, draw.OverrunModeThreeDot, cOpts...), + draw.BorderTitle(c.opts.borderTitle, draw.OverrunModeThreeDot, titleCOpts...), draw.BorderTitleAlign(c.opts.borderTitleHAlign), draw.BorderCellOpts(cOpts...), ); err != nil { diff --git a/container/draw_test.go b/container/draw_test.go index 9789772..76c14d7 100644 --- a/container/draw_test.go +++ b/container/draw_test.go @@ -502,6 +502,44 @@ func TestDrawWidget(t *testing.T) { return ft }, }, + { + desc: "draws widget with container border and title with different color and focus color", + termSize: image.Point{9, 5}, + container: func(ft *faketerm.Terminal) (*Container, error) { + return New( + ft, + Border(linestyle.Light), + BorderTitle("ab"), + TitleColor(cell.ColorBlue), + // The created container is in focus so we must set the focus color + // in order to see the difference. + TitleFocusedColor(cell.ColorBlue), + BorderTitleAlignLeft(), + PlaceWidget(fakewidget.New(widgetapi.Options{})), + ) + }, + want: func(size image.Point) *faketerm.Terminal { + ft := faketerm.MustNew(size) + cvs := testcanvas.MustNew(ft.Area()) + // Container border. + testdraw.MustBorder( + cvs, + cvs.Area(), + draw.BorderCellOpts(cell.FgColor(cell.ColorYellow)), + draw.BorderTitle( + "ab", + draw.OverrunModeThreeDot, + cell.FgColor(cell.ColorBlue), + ), + ) + + // Fake widget border. + testdraw.MustBorder(cvs, image.Rect(1, 1, 8, 4)) + testdraw.MustText(cvs, "(7,3)", image.Point{2, 2}) + testcanvas.MustApply(cvs, ft) + return ft + }, + }, { desc: "draws widget without container border", termSize: image.Point{9, 5}, diff --git a/container/options.go b/container/options.go index 795e61c..1fa718a 100644 --- a/container/options.go +++ b/container/options.go @@ -194,6 +194,10 @@ type inherited struct { borderColor cell.Color // focusedColor is the color used for the border when focused. focusedColor cell.Color + // titleColor is the color used for the title. + titleColor *cell.Color + // titleFocusedColor is the color used for the title when focused. + titleFocusedColor *cell.Color } // focusGroups maps focus group numbers that have the same key assigned. @@ -749,6 +753,25 @@ func FocusedColor(color cell.Color) Option { }) } +// TitleColor sets the color of the title around the container. +// This option is inherited to sub containers created by container splits. +func TitleColor(color cell.Color) Option { + return option(func(c *Container) error { + c.opts.inherited.titleColor = &color + return nil + }) +} + +// TitleFocusedColor sets the color of the container title when it has +// keyboard focus. +// This option is inherited to sub containers created by container splits. +func TitleFocusedColor(color cell.Color) Option { + return option(func(c *Container) error { + c.opts.inherited.titleFocusedColor = &color + return nil + }) +} + // splitType identifies how a container is split. type splitType int