mirror of https://github.com/mum4k/termdash.git
116 lines
3.2 KiB
Go
116 lines
3.2 KiB
Go
// Copyright 2019 Google Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package segmentdisplay
|
|
|
|
// segment_area.go contains code that determines how many segments we can fit
|
|
// in the canvas.
|
|
|
|
import (
|
|
"fmt"
|
|
"image"
|
|
|
|
"github.com/mum4k/termdash/draw/segdisp/sixteen"
|
|
)
|
|
|
|
// segArea contains information about the area that will contain the segments.
|
|
type segArea struct {
|
|
// segment is the area for one segment.
|
|
segment image.Rectangle
|
|
// canFit is the number of segments we can fit on the canvas.
|
|
canFit int
|
|
// gapPixels is the size of gaps between segments in pixels.
|
|
gapPixels int
|
|
// gaps is the number of gaps that will be drawn.
|
|
gaps int
|
|
}
|
|
|
|
// needArea returns the complete area required for all the segments that we can
|
|
// fit and any gaps.
|
|
func (sa *segArea) needArea() image.Rectangle {
|
|
return image.Rect(
|
|
0,
|
|
0,
|
|
sa.segment.Dx()*sa.canFit+sa.gaps*sa.gapPixels,
|
|
sa.segment.Dy(),
|
|
)
|
|
}
|
|
|
|
// newSegArea calculates the area for segments given available canvas area,
|
|
// length of the text to be displayed and the size of gap between segments
|
|
func newSegArea(cvsAr image.Rectangle, textLen, gapPercent int) (*segArea, error) {
|
|
segAr, err := sixteen.Required(cvsAr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("sixteen.Required => %v", err)
|
|
}
|
|
gapPixels := segAr.Dy() * gapPercent / 100
|
|
|
|
var (
|
|
gaps int
|
|
canFit int
|
|
taken int
|
|
)
|
|
for i := 0; i < textLen; i++ {
|
|
taken += segAr.Dx()
|
|
|
|
if taken > cvsAr.Dx() {
|
|
break
|
|
}
|
|
canFit++
|
|
|
|
// Don't insert gaps after the last segment in the text or the last
|
|
// segment we can fit.
|
|
if gapPixels == 0 || i == textLen-1 {
|
|
continue
|
|
}
|
|
|
|
remaining := cvsAr.Dx() - taken
|
|
// Only insert gaps if we can still fit one more segment with the gap.
|
|
if remaining >= gapPixels+segAr.Dx() {
|
|
taken += gapPixels
|
|
gaps++
|
|
} else {
|
|
// Gap is needed but doesn't fit together with the next segment.
|
|
// So insert neither.
|
|
break
|
|
}
|
|
}
|
|
return &segArea{
|
|
segment: segAr,
|
|
canFit: canFit,
|
|
gapPixels: gapPixels,
|
|
gaps: gaps,
|
|
}, nil
|
|
}
|
|
|
|
// maximizeFit finds the largest individual segment size that enables us to fit
|
|
// the most characters onto a canvas with the provided area. Returns the area
|
|
// required for a single segment and the number of segments we can fit.
|
|
func maximizeFit(cvsAr image.Rectangle, textLen, gapPercent int) (*segArea, error) {
|
|
var bestSegAr *segArea
|
|
for height := cvsAr.Dy(); height >= sixteen.MinRows; height-- {
|
|
cvsAr := image.Rect(cvsAr.Min.X, cvsAr.Min.Y, cvsAr.Max.X, cvsAr.Min.Y+height)
|
|
segAr, err := newSegArea(cvsAr, textLen, gapPercent)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if segAr.canFit >= textLen {
|
|
return segAr, nil
|
|
}
|
|
bestSegAr = segAr
|
|
}
|
|
return bestSegAr, nil
|
|
}
|