diff --git a/CHANGELOG b/CHANGELOG index af51a8c..74750de 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,6 +17,7 @@ v1.5.1 (WIP) - Generalize tag stripping as StripTags - Make printWithStyle public and rename as PrintStyle - Optimize TextView (writing is 90% faster, drawing is 50% faster) +- Reduce Box inner rect calculations - Remove return values from methods which return their primitive (breaks chaining) - Remove Application.ForceDraw (Application.Draw may be called anywhere) - Rename SetBorderPadding and GetBorderPadding as SetPadding and GetPadding diff --git a/box.go b/box.go index 7a794eb..26ab10c 100644 --- a/box.go +++ b/box.go @@ -13,15 +13,15 @@ type Box struct { // The position of the rect. x, y, width, height int + // Padding. + paddingTop, paddingBottom, paddingLeft, paddingRight int + // The inner rect reserved for the box's content. innerX, innerY, innerWidth, innerHeight int // Whether or not the box is visible. visible bool - // Padding. - paddingTop, paddingBottom, paddingLeft, paddingRight int - // The border color when the box has focus. borderColorFocused tcell.Color @@ -81,7 +81,6 @@ func NewBox() *Box { b := &Box{ width: 15, height: 10, - innerX: -1, // Mark as uninitialized. visible: true, backgroundColor: Styles.PrimitiveBackgroundColor, borderColor: Styles.BorderColor, @@ -91,13 +90,43 @@ func NewBox() *Box { showFocus: true, } b.focus = b + b.updateInnerRect() return b } +func (b *Box) updateInnerRect() { + x, y, width, height := b.x, b.y, b.width, b.height + + // Subtract border space + if b.border { + x++ + y++ + width -= 2 + height -= 2 + } + + // Subtract padding + x, y, width, height = + x+b.paddingLeft, + y+b.paddingTop, + width-b.paddingLeft-b.paddingRight, + height-b.paddingTop-b.paddingBottom + + if width < 0 { + width = 0 + } + if height < 0 { + height = 0 + } + + b.innerX, b.innerY, b.innerWidth, b.innerHeight = x, y, width, height +} + // GetPadding returns the size of the padding around the box content. func (b *Box) GetPadding() (top, bottom, left, right int) { b.l.RLock() defer b.l.RUnlock() + return b.paddingTop, b.paddingBottom, b.paddingLeft, b.paddingRight } @@ -107,6 +136,8 @@ func (b *Box) SetPadding(top, bottom, left, right int) { defer b.l.Unlock() b.paddingTop, b.paddingBottom, b.paddingLeft, b.paddingRight = top, bottom, left, right + + b.updateInnerRect() } // GetRect returns the current position of the rectangle, x, y, width, and @@ -123,32 +154,9 @@ func (b *Box) GetRect() (int, int, int, int) { // will clamp to 0 and thus never be negative. func (b *Box) GetInnerRect() (int, int, int, int) { b.l.RLock() - if b.innerX >= 0 { - defer b.l.RUnlock() - return b.innerX, b.innerY, b.innerWidth, b.innerHeight - } - b.l.RUnlock() + defer b.l.RUnlock() - x, y, width, height := b.GetRect() - b.l.RLock() - if b.border { - x++ - y++ - width -= 2 - height -= 2 - } - x, y, width, height = x+b.paddingLeft, - y+b.paddingTop, - width-b.paddingLeft-b.paddingRight, - height-b.paddingTop-b.paddingBottom - if width < 0 { - width = 0 - } - if height < 0 { - height = 0 - } - b.l.RUnlock() - return x, y, width, height + return b.innerX, b.innerY, b.innerWidth, b.innerHeight } // SetRect sets a new position of the primitive. Note that this has no effect @@ -160,11 +168,9 @@ func (b *Box) SetRect(x, y, width, height int) { b.l.Lock() defer b.l.Unlock() - b.x = x - b.y = y - b.width = width - b.height = height - b.innerX = -1 // Mark inner rect as uninitialized. + b.x, b.y, b.width, b.height = x, y, width, height + + b.updateInnerRect() } // SetVisible sets the flag indicating whether or not the box is visible. @@ -353,6 +359,8 @@ func (b *Box) SetBorder(show bool) { defer b.l.Unlock() b.border = show + + b.updateInnerRect() } // SetBorderColor sets the box's border color. @@ -417,16 +425,15 @@ func (b *Box) SetTitleAlign(align int) { // Draw draws this primitive onto the screen. func (b *Box) Draw(screen tcell.Screen) { b.l.Lock() + defer b.l.Unlock() // Don't draw anything if the box is hidden if !b.visible { - b.l.Unlock() return } // Don't draw anything if there is no space. if b.width <= 0 || b.height <= 0 { - b.l.Unlock() return } @@ -499,43 +506,8 @@ func (b *Box) Draw(screen tcell.Screen) { // Call custom draw function. if b.draw != nil { - b.l.Unlock() - newX, newY, newWidth, newHeight := b.draw(screen, b.x, b.y, b.width, b.height) - b.l.Lock() - b.innerX, b.innerY, b.innerWidth, b.innerHeight = newX, newY, newWidth, newHeight - } else { - // Remember the inner rect. - b.innerX = -1 - b.l.Unlock() - newX, newY, newWidth, newHeight := b.GetInnerRect() - b.l.Lock() - b.innerX, b.innerY, b.innerWidth, b.innerHeight = newX, newY, newWidth, newHeight - } - - // Clamp inner rect to screen. - width, height := screen.Size() - if b.innerX < 0 { - b.innerWidth += b.innerX - b.innerX = 0 - } - if b.innerX+b.innerWidth >= width { - b.innerWidth = width - b.innerX - } - if b.innerY+b.innerHeight >= height { - b.innerHeight = height - b.innerY - } - if b.innerY < 0 { - b.innerHeight += b.innerY - b.innerY = 0 + b.innerX, b.innerY, b.innerWidth, b.innerHeight = b.draw(screen, b.x, b.y, b.width, b.height) } - if b.innerWidth < 0 { - b.innerWidth = 0 - } - if b.innerHeight < 0 { - b.innerHeight = 0 - } - - b.l.Unlock() } // ShowFocus sets the flag indicating whether or not the borders of this diff --git a/windowmanager.go b/windowmanager.go index 40eefa8..d0d0db1 100644 --- a/windowmanager.go +++ b/windowmanager.go @@ -141,6 +141,7 @@ func (wm *WindowManager) MouseHandler() func(action MouseAction, event *tcell.Ev w.x -= offsetX + w.dragWX w.y -= offsetY + w.dragWY + w.updateInnerRect() consumed = true } @@ -160,6 +161,7 @@ func (wm *WindowManager) MouseHandler() func(action MouseAction, event *tcell.Ev } } + w.updateInnerRect() consumed = true } @@ -179,6 +181,7 @@ func (wm *WindowManager) MouseHandler() func(action MouseAction, event *tcell.Ev } } + w.updateInnerRect() consumed = true } }