github.com/utopiagio/gio@v0.0.8/widget/fit.go (about)

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  package widget
     4  
     5  import (
     6  	"image"
     7  
     8  	"github.com/utopiagio/gio/f32"
     9  	"github.com/utopiagio/gio/layout"
    10  )
    11  
    12  // Fit scales a widget to fit and clip to the constraints.
    13  type Fit uint8
    14  
    15  const (
    16  	// Unscaled does not alter the scale of a widget.
    17  	Unscaled Fit = iota
    18  	// Contain scales widget as large as possible without cropping
    19  	// and it preserves aspect-ratio.
    20  	Contain
    21  	// Cover scales the widget to cover the constraint area and
    22  	// preserves aspect-ratio.
    23  	Cover
    24  	// ScaleDown scales the widget smaller without cropping,
    25  	// when it exceeds the constraint area.
    26  	// It preserves aspect-ratio.
    27  	ScaleDown
    28  	// Fill stretches the widget to the constraints and does not
    29  	// preserve aspect-ratio.
    30  	Fill
    31  )
    32  
    33  // scale computes the new dimensions and transformation required to fit dims to cs, given the position.
    34  func (fit Fit) scale(cs layout.Constraints, pos layout.Direction, dims layout.Dimensions) (layout.Dimensions, f32.Affine2D) {
    35  	widgetSize := dims.Size
    36  
    37  	if fit == Unscaled || dims.Size.X == 0 || dims.Size.Y == 0 {
    38  		dims.Size = cs.Constrain(dims.Size)
    39  
    40  		offset := pos.Position(widgetSize, dims.Size)
    41  		dims.Baseline += offset.Y
    42  		return dims, f32.Affine2D{}.Offset(layout.FPt(offset))
    43  	}
    44  
    45  	scale := f32.Point{
    46  		X: float32(cs.Max.X) / float32(dims.Size.X),
    47  		Y: float32(cs.Max.Y) / float32(dims.Size.Y),
    48  	}
    49  
    50  	switch fit {
    51  	case Contain:
    52  		if scale.Y < scale.X {
    53  			scale.X = scale.Y
    54  		} else {
    55  			scale.Y = scale.X
    56  		}
    57  	case Cover:
    58  		if scale.Y > scale.X {
    59  			scale.X = scale.Y
    60  		} else {
    61  			scale.Y = scale.X
    62  		}
    63  	case ScaleDown:
    64  		if scale.Y < scale.X {
    65  			scale.X = scale.Y
    66  		} else {
    67  			scale.Y = scale.X
    68  		}
    69  
    70  		// The widget would need to be scaled up, no change needed.
    71  		if scale.X >= 1 {
    72  			dims.Size = cs.Constrain(dims.Size)
    73  
    74  			offset := pos.Position(widgetSize, dims.Size)
    75  			dims.Baseline += offset.Y
    76  			return dims, f32.Affine2D{}.Offset(layout.FPt(offset))
    77  		}
    78  	case Fill:
    79  	}
    80  
    81  	var scaledSize image.Point
    82  	scaledSize.X = int(float32(widgetSize.X) * scale.X)
    83  	scaledSize.Y = int(float32(widgetSize.Y) * scale.Y)
    84  	dims.Size = cs.Constrain(scaledSize)
    85  	dims.Baseline = int(float32(dims.Baseline) * scale.Y)
    86  
    87  	offset := pos.Position(scaledSize, dims.Size)
    88  	trans := f32.Affine2D{}.
    89  		Scale(f32.Point{}, scale).
    90  		Offset(layout.FPt(offset))
    91  
    92  	dims.Baseline += offset.Y
    93  
    94  	return dims, trans
    95  }