aboutsummaryrefslogblamecommitdiffstats
path: root/vendor/github.com/gizak/termui/block.go
blob: 3e8571bc232639b55e18a786e6b1f6128456a317 (plain) (tree)
1
2
3
4
5
6
                                                                       




                                                                
























































































                                                                                                          



                                                            

                                     

                         











                               

                         



                         

                            



                                                                      

















                                               
 


                            
 































                                                          



                                                                          


                                               



                                        

                                 
 


                                         
 

                              
 
                  



                                          

                                


                                                                         

                             


                                                                        

                             


                                                                   

                                 
 













                                                        
// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.

package termui

import "image"

// Hline is a horizontal line.
type Hline struct {
    X   int
    Y   int
    Len int
    Fg  Attribute
    Bg  Attribute
}

// Vline is a vertical line.
type Vline struct {
    X   int
    Y   int
    Len int
    Fg  Attribute
    Bg  Attribute
}

// Buffer draws a horizontal line.
func (l Hline) Buffer() Buffer {
    if l.Len <= 0 {
        return NewBuffer()
    }
    return NewFilledBuffer(l.X, l.Y, l.X+l.Len, l.Y+1, HORIZONTAL_LINE, l.Fg, l.Bg)
}

// Buffer draws a vertical line.
func (l Vline) Buffer() Buffer {
    if l.Len <= 0 {
        return NewBuffer()
    }
    return NewFilledBuffer(l.X, l.Y, l.X+1, l.Y+l.Len, VERTICAL_LINE, l.Fg, l.Bg)
}

// Buffer draws a box border.
func (b Block) drawBorder(buf Buffer) {
    if !b.Border {
        return
    }

    min := b.area.Min
    max := b.area.Max

    x0 := min.X
    y0 := min.Y
    x1 := max.X - 1
    y1 := max.Y - 1

    // draw lines
    if b.BorderTop {
        buf.Merge(Hline{x0, y0, x1 - x0, b.BorderFg, b.BorderBg}.Buffer())
    }
    if b.BorderBottom {
        buf.Merge(Hline{x0, y1, x1 - x0, b.BorderFg, b.BorderBg}.Buffer())
    }
    if b.BorderLeft {
        buf.Merge(Vline{x0, y0, y1 - y0, b.BorderFg, b.BorderBg}.Buffer())
    }
    if b.BorderRight {
        buf.Merge(Vline{x1, y0, y1 - y0, b.BorderFg, b.BorderBg}.Buffer())
    }

    // draw corners
    if b.BorderTop && b.BorderLeft && b.area.Dx() > 0 && b.area.Dy() > 0 {
        buf.Set(x0, y0, Cell{TOP_LEFT, b.BorderFg, b.BorderBg})
    }
    if b.BorderTop && b.BorderRight && b.area.Dx() > 1 && b.area.Dy() > 0 {
        buf.Set(x1, y0, Cell{TOP_RIGHT, b.BorderFg, b.BorderBg})
    }
    if b.BorderBottom && b.BorderLeft && b.area.Dx() > 0 && b.area.Dy() > 1 {
        buf.Set(x0, y1, Cell{BOTTOM_LEFT, b.BorderFg, b.BorderBg})
    }
    if b.BorderBottom && b.BorderRight && b.area.Dx() > 1 && b.area.Dy() > 1 {
        buf.Set(x1, y1, Cell{BOTTOM_RIGHT, b.BorderFg, b.BorderBg})
    }
}

func (b Block) drawBorderLabel(buf Buffer) {
    maxTxtW := b.area.Dx() - 2
    tx := DTrimTxCls(DefaultTxBuilder.Build(b.BorderLabel, b.BorderLabelFg, b.BorderLabelBg), maxTxtW)

    for i, w := 0, 0; i < len(tx); i++ {
        buf.Set(b.area.Min.X+1+w, b.area.Min.Y, tx[i])
        w += tx[i].Width()
    }
}

// Block is a base struct for all other upper level widgets,
// consider it as css: display:block.
// Normally you do not need to create it manually.
type Block struct {
    area          image.Rectangle
    innerArea     image.Rectangle
    X             int
    Y             int
    Border        bool
    BorderFg      Attribute
    BorderBg      Attribute
    BorderLeft    bool
    BorderRight   bool
    BorderTop     bool
    BorderBottom  bool
    BorderLabel   string
    BorderLabelFg Attribute
    BorderLabelBg Attribute
    Display       bool
    Bg            Attribute
    Width         int
    Height        int
    PaddingTop    int
    PaddingBottom int
    PaddingLeft   int
    PaddingRight  int
    id            string
    Float         Align
}

// NewBlock returns a *Block which inherits styles from current theme.
func NewBlock() *Block {
    b := Block{}
    b.Display = true
    b.Border = true
    b.BorderLeft = true
    b.BorderRight = true
    b.BorderTop = true
    b.BorderBottom = true
    b.BorderBg = ThemeAttr("border.bg")
    b.BorderFg = ThemeAttr("border.fg")
    b.BorderLabelBg = ThemeAttr("label.bg")
    b.BorderLabelFg = ThemeAttr("label.fg")
    b.Bg = ThemeAttr("block.bg")
    b.Width = 2
    b.Height = 2
    b.id = GenId()
    b.Float = AlignNone
    return &b
}

func (b Block) Id() string {
    return b.id
}

// Align computes box model
func (b *Block) Align() {
    // outer
    b.area.Min.X = 0
    b.area.Min.Y = 0
    b.area.Max.X = b.Width
    b.area.Max.Y = b.Height

    // float
    b.area = AlignArea(TermRect(), b.area, b.Float)
    b.area = MoveArea(b.area, b.X, b.Y)

    // inner
    b.innerArea.Min.X = b.area.Min.X + b.PaddingLeft
    b.innerArea.Min.Y = b.area.Min.Y + b.PaddingTop
    b.innerArea.Max.X = b.area.Max.X - b.PaddingRight
    b.innerArea.Max.Y = b.area.Max.Y - b.PaddingBottom

    if b.Border {
        if b.BorderLeft {
            b.innerArea.Min.X++
        }
        if b.BorderRight {
            b.innerArea.Max.X--
        }
        if b.BorderTop {
            b.innerArea.Min.Y++
        }
        if b.BorderBottom {
            b.innerArea.Max.Y--
        }
    }
}

// InnerBounds returns the internal bounds of the block after aligning and
// calculating the padding and border, if any.
func (b *Block) InnerBounds() image.Rectangle {
    b.Align()
    return b.innerArea
}

// Buffer implements Bufferer interface.
// Draw background and border (if any).
func (b *Block) Buffer() Buffer {
    b.Align()

    buf := NewBuffer()
    buf.SetArea(b.area)
    buf.Fill(' ', ColorDefault, b.Bg)

    b.drawBorder(buf)
    b.drawBorderLabel(buf)

    return buf
}

// GetHeight implements GridBufferer.
// It returns current height of the block.
func (b Block) GetHeight() int {
    return b.Height
}

// SetX implements GridBufferer interface, which sets block's x position.
func (b *Block) SetX(x int) {
    b.X = x
}

// SetY implements GridBufferer interface, it sets y position for block.
func (b *Block) SetY(y int) {
    b.Y = y
}

// SetWidth implements GridBuffer interface, it sets block's width.
func (b *Block) SetWidth(w int) {
    b.Width = w
}

func (b Block) InnerWidth() int {
    return b.innerArea.Dx()
}

func (b Block) InnerHeight() int {
    return b.innerArea.Dy()
}

func (b Block) InnerX() int {
    return b.innerArea.Min.X
}

func (b Block) InnerY() int { return b.innerArea.Min.Y }