style: customize vertical and horizontal border characters
New border-char-horizontal and border-char-vertical config settings in aerc.conf allow users to modify border appearance from the default 1-wide/tall blank space. In stylesets, border.fg now affects the foreground color when custom characters are defined. Signed-off-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
parent
ad5f65b927
commit
f776fb8246
7 changed files with 58 additions and 8 deletions
|
@ -94,6 +94,12 @@ next-message-on-delete=true
|
||||||
# default: @SHAREDIR@/stylesets/
|
# default: @SHAREDIR@/stylesets/
|
||||||
stylesets-dirs=@SHAREDIR@/stylesets/
|
stylesets-dirs=@SHAREDIR@/stylesets/
|
||||||
|
|
||||||
|
# Uncomment to use box-drawing characters for vertical and horizontal borders.
|
||||||
|
#
|
||||||
|
# Default: spaces
|
||||||
|
# border-char-vertical=│
|
||||||
|
# border-char-horizontal=─
|
||||||
|
|
||||||
# Sets the styleset to use for the aerc ui elements.
|
# Sets the styleset to use for the aerc ui elements.
|
||||||
#
|
#
|
||||||
# Default: default
|
# Default: default
|
||||||
|
|
|
@ -53,6 +53,9 @@ type UIConfig struct {
|
||||||
StyleSetDirs []string `ini:"stylesets-dirs" delim:":"`
|
StyleSetDirs []string `ini:"stylesets-dirs" delim:":"`
|
||||||
StyleSetName string `ini:"styleset-name"`
|
StyleSetName string `ini:"styleset-name"`
|
||||||
style StyleSet
|
style StyleSet
|
||||||
|
// customize border appearance
|
||||||
|
BorderCharVertical rune `ini:"-"`
|
||||||
|
BorderCharHorizontal rune `ini:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContextType int
|
type ContextType int
|
||||||
|
@ -358,6 +361,9 @@ func (config *AercConfig) LoadConfig(file *ini.File) error {
|
||||||
if err := ui.MapTo(&config.Ui); err != nil {
|
if err := ui.MapTo(&config.Ui); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := validateBorderChars(ui, &config.Ui); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for _, sectionName := range file.SectionStrings() {
|
for _, sectionName := range file.SectionStrings() {
|
||||||
if !strings.Contains(sectionName, "ui:") {
|
if !strings.Contains(sectionName, "ui:") {
|
||||||
|
@ -372,6 +378,9 @@ func (config *AercConfig) LoadConfig(file *ini.File) error {
|
||||||
if err := uiSection.MapTo(&uiSubConfig); err != nil {
|
if err := uiSection.MapTo(&uiSubConfig); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := validateBorderChars(uiSection, &uiSubConfig); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
contextualUi :=
|
contextualUi :=
|
||||||
UIConfigContext{
|
UIConfigContext{
|
||||||
UiConfig: uiSubConfig,
|
UiConfig: uiSubConfig,
|
||||||
|
@ -461,6 +470,26 @@ func (config *AercConfig) LoadConfig(file *ini.File) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateBorderChars(section *ini.Section, config *UIConfig) error {
|
||||||
|
for key, val := range section.KeysHash() {
|
||||||
|
switch key {
|
||||||
|
case "border-char-vertical":
|
||||||
|
char := []rune(val)
|
||||||
|
if len(char) != 1 {
|
||||||
|
return fmt.Errorf("%v must be one and only one character", key)
|
||||||
|
}
|
||||||
|
config.BorderCharVertical = char[0]
|
||||||
|
case "border-char-horizontal":
|
||||||
|
char := []rune(val)
|
||||||
|
if len(char) != 1 {
|
||||||
|
return fmt.Errorf("%v must be one and only one character", key)
|
||||||
|
}
|
||||||
|
config.BorderCharHorizontal = char[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) {
|
func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) {
|
||||||
if root == nil {
|
if root == nil {
|
||||||
_root := path.Join(xdg.ConfigHome(), "aerc")
|
_root := path.Join(xdg.ConfigHome(), "aerc")
|
||||||
|
@ -524,6 +553,9 @@ func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) {
|
||||||
CompletionPopovers: true,
|
CompletionPopovers: true,
|
||||||
StyleSetDirs: []string{path.Join(sharedir, "stylesets")},
|
StyleSetDirs: []string{path.Join(sharedir, "stylesets")},
|
||||||
StyleSetName: "default",
|
StyleSetName: "default",
|
||||||
|
// border defaults
|
||||||
|
BorderCharVertical: ' ',
|
||||||
|
BorderCharHorizontal: ' ',
|
||||||
},
|
},
|
||||||
|
|
||||||
ContextualUis: []UIConfigContext{},
|
ContextualUis: []UIConfigContext{},
|
||||||
|
|
|
@ -192,6 +192,13 @@ These options are configured in the *[ui]* section of aerc.conf.
|
||||||
|
|
||||||
Default: 250ms
|
Default: 250ms
|
||||||
|
|
||||||
|
*border-char-vertical*
|
||||||
|
*border-char-horizontal*
|
||||||
|
Set stylable characters (via the 'border' element) for vertical and
|
||||||
|
horizontal borders.
|
||||||
|
|
||||||
|
Default: spaces
|
||||||
|
|
||||||
*stylesets-dirs*
|
*stylesets-dirs*
|
||||||
The directories where the stylesets are stored. The config takes a
|
The directories where the stylesets are stored. The config takes a
|
||||||
colon-separated list of dirs.
|
colon-separated list of dirs.
|
||||||
|
|
|
@ -128,7 +128,7 @@ styling.
|
||||||
| spinner
|
| spinner
|
||||||
: The style for the loading spinner.
|
: The style for the loading spinner.
|
||||||
| border
|
| border
|
||||||
: The style used to draw borders. *Only the background color is used*.
|
: The style used to draw borders. *Only the background color is used unless you customize border-char-vertical and/or border-char-horizontal in aerc.conf*.
|
||||||
| selector_default
|
| selector_default
|
||||||
: The default style for the selector ui element.
|
: The default style for the selector ui element.
|
||||||
| selector_focused
|
| selector_focused
|
||||||
|
|
|
@ -50,22 +50,25 @@ func (bordered *Bordered) Draw(ctx *Context) {
|
||||||
width := ctx.Width()
|
width := ctx.Width()
|
||||||
height := ctx.Height()
|
height := ctx.Height()
|
||||||
style := bordered.uiConfig.GetStyle(config.STYLE_BORDER)
|
style := bordered.uiConfig.GetStyle(config.STYLE_BORDER)
|
||||||
|
verticalChar := bordered.uiConfig.BorderCharVertical
|
||||||
|
horizontalChar := bordered.uiConfig.BorderCharHorizontal
|
||||||
|
|
||||||
if bordered.borders&BORDER_LEFT != 0 {
|
if bordered.borders&BORDER_LEFT != 0 {
|
||||||
ctx.Fill(0, 0, 1, ctx.Height(), ' ', style)
|
ctx.Fill(0, 0, 1, ctx.Height(), verticalChar, style)
|
||||||
x += 1
|
x += 1
|
||||||
width -= 1
|
width -= 1
|
||||||
}
|
}
|
||||||
if bordered.borders&BORDER_TOP != 0 {
|
if bordered.borders&BORDER_TOP != 0 {
|
||||||
ctx.Fill(0, 0, ctx.Width(), 1, ' ', style)
|
ctx.Fill(0, 0, ctx.Width(), 1, horizontalChar, style)
|
||||||
y += 1
|
y += 1
|
||||||
height -= 1
|
height -= 1
|
||||||
}
|
}
|
||||||
if bordered.borders&BORDER_RIGHT != 0 {
|
if bordered.borders&BORDER_RIGHT != 0 {
|
||||||
ctx.Fill(ctx.Width()-1, 0, 1, ctx.Height(), ' ', style)
|
ctx.Fill(ctx.Width()-1, 0, 1, ctx.Height(), verticalChar, style)
|
||||||
width -= 1
|
width -= 1
|
||||||
}
|
}
|
||||||
if bordered.borders&BORDER_BOTTOM != 0 {
|
if bordered.borders&BORDER_BOTTOM != 0 {
|
||||||
ctx.Fill(0, ctx.Height()-1, ctx.Width(), 1, ' ', style)
|
ctx.Fill(0, ctx.Height()-1, ctx.Width(), 1, horizontalChar, style)
|
||||||
height -= 1
|
height -= 1
|
||||||
}
|
}
|
||||||
subctx := ctx.Subcontext(x, y, width, height)
|
subctx := ctx.Subcontext(x, y, width, height)
|
||||||
|
|
|
@ -679,9 +679,10 @@ func (c *Composer) updateGrid() {
|
||||||
c.grid.RemoveChild(c.heditors)
|
c.grid.RemoveChild(c.heditors)
|
||||||
}
|
}
|
||||||
borderStyle := c.config.Ui.GetStyle(config.STYLE_BORDER)
|
borderStyle := c.config.Ui.GetStyle(config.STYLE_BORDER)
|
||||||
|
borderChar := c.config.Ui.BorderCharHorizontal
|
||||||
c.heditors = heditors
|
c.heditors = heditors
|
||||||
c.grid.AddChild(c.heditors).At(0, 0)
|
c.grid.AddChild(c.heditors).At(0, 0)
|
||||||
c.grid.AddChild(ui.NewFill(' ', borderStyle)).At(1, 0)
|
c.grid.AddChild(ui.NewFill(borderChar, borderStyle)).At(1, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Composer) reloadEmail() error {
|
func (c *Composer) reloadEmail() error {
|
||||||
|
|
|
@ -106,14 +106,15 @@ func NewMessageViewer(acct *AccountView,
|
||||||
}
|
}
|
||||||
|
|
||||||
borderStyle := acct.UiConfig().GetStyle(config.STYLE_BORDER)
|
borderStyle := acct.UiConfig().GetStyle(config.STYLE_BORDER)
|
||||||
|
borderChar := acct.UiConfig().BorderCharHorizontal
|
||||||
|
|
||||||
grid.AddChild(header).At(0, 0)
|
grid.AddChild(header).At(0, 0)
|
||||||
if msg.PGPDetails() != nil {
|
if msg.PGPDetails() != nil {
|
||||||
grid.AddChild(NewPGPInfo(msg.PGPDetails(), acct.UiConfig())).At(1, 0)
|
grid.AddChild(NewPGPInfo(msg.PGPDetails(), acct.UiConfig())).At(1, 0)
|
||||||
grid.AddChild(ui.NewFill(' ', borderStyle)).At(2, 0)
|
grid.AddChild(ui.NewFill(borderChar, borderStyle)).At(2, 0)
|
||||||
grid.AddChild(switcher).At(3, 0)
|
grid.AddChild(switcher).At(3, 0)
|
||||||
} else {
|
} else {
|
||||||
grid.AddChild(ui.NewFill(' ', borderStyle)).At(1, 0)
|
grid.AddChild(ui.NewFill(borderChar, borderStyle)).At(1, 0)
|
||||||
grid.AddChild(switcher).At(2, 0)
|
grid.AddChild(switcher).At(2, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue