Skip to content

Commit

Permalink
DPI: Revise 1/96" to/from native pixel conversions
Browse files Browse the repository at this point in the history
The metric types have been (temporarily) replaced by typed int. Pixels
have been split to `type Pixel96DPI int` and `type Pixel int`. The
former represents 1/96" pixels, the later represents native pixels.

By switching to separate sets of metric types Go errored everywhere
where DPI conversion was missing or was excessive.

All incompatibilities were revised - some were fixed, others were marked
by "TODO" to get fixed in future commits.

Furthermore, Canvas was extended to provide `...Pixels` method variants.

Signed-off-by: Simon Rozman <simon@rozman.si>
  • Loading branch information
rozmansi committed Sep 26, 2019
1 parent 1f5fa83 commit 20effb6
Show file tree
Hide file tree
Showing 61 changed files with 1,090 additions and 744 deletions.
15 changes: 7 additions & 8 deletions bitmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func NewBitmapWithTransparentPixels(size Size) (*Bitmap, error) {

func newBitmap(size Size, transparent bool) (bmp *Bitmap, err error) {
err = withCompatibleDC(func(hdc win.HDC) error {
bufSize := size.Width * size.Height * 4
bufSize := int(size.Width * size.Height * 4)

var hdr win.BITMAPINFOHEADER
hdr.BiSize = uint32(unsafe.Sizeof(hdr))
Expand Down Expand Up @@ -159,9 +159,7 @@ func NewBitmapFromImageWithSize(image Image, size Size) (*Bitmap, error) {
canvas.dpix = dpi
canvas.dpiy = dpi

size = SizeTo96DPI(size, dpi)

if err := canvas.DrawImageStretched(image, Rectangle{0, 0, size.Width, size.Height}); err != nil {
if err := canvas.DrawImageStretchedPixels(image, Rectangle{0, 0, size.Width, size.Height}); err != nil {
return nil, err
}

Expand Down Expand Up @@ -272,8 +270,9 @@ func (bmp *Bitmap) Dispose() {
}
}

func (bmp *Bitmap) Size() Size {
return bmp.size
func (bmp *Bitmap) Size() Size96DPI {
// TODO: Handle DPI
return bmp.size.To96DPI(96)
}

func (bmp *Bitmap) handle() win.HBITMAP {
Expand Down Expand Up @@ -356,8 +355,8 @@ func newBitmapFromHBITMAP(hBmp win.HBITMAP) (bmp *Bitmap, err error) {
hBmp: hBmp,
hPackedDIB: hPackedDIB,
size: Size{
int(bmih.BiWidth),
int(bmih.BiHeight),
Pixel(bmih.BiWidth),
Pixel(bmih.BiHeight),
},
}, nil
}
Expand Down
77 changes: 41 additions & 36 deletions boxlayout.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type BoxLayout struct {
func newBoxLayout(orientation Orientation) *BoxLayout {
l := &BoxLayout{
LayoutBase: LayoutBase{
margins96dpi: Margins{9, 9, 9, 9},
margins96dpi: Margins96DPI{9, 9, 9, 9},
spacing96dpi: 6,
},
orientation: orientation,
Expand Down Expand Up @@ -116,8 +116,8 @@ func (l *BoxLayout) CreateLayoutItem(ctx *LayoutContext) ContainerLayoutItem {

type boxLayoutItemInfo struct {
index int
minSize int
maxSize int
minSize Pixel
maxSize Pixel
stretch int
greedy bool
item LayoutItem
Expand All @@ -138,7 +138,7 @@ func (l boxLayoutItemInfoList) Less(i, j int) bool {
minDiff := l[i].minSize - l[j].minSize

if minDiff == 0 {
return l[i].maxSize/l[i].stretch < l[j].maxSize/l[j].stretch
return int(l[i].maxSize)/l[i].stretch < int(l[j].maxSize)/l[j].stretch
}

return minDiff > 0
Expand Down Expand Up @@ -174,7 +174,7 @@ func (li *boxLayoutItem) MinSize() Size {
return li.MinSizeForSize(li.geometry.ClientSize)
}

func (li *boxLayoutItem) HeightForWidth(width int) int {
func (li *boxLayoutItem) HeightForWidth(width Pixel) Pixel {
return li.MinSizeForSize(Size{width, li.geometry.ClientSize.Height}).Height
}

Expand All @@ -190,9 +190,10 @@ func (li *boxLayoutItem) MinSizeForSize(size Size) Size {

items := boxLayoutItems(li, itemsToLayout(li.children), li.orientation, li.alignment, bounds, li.margins, li.spacing, li.hwnd2StretchFactor)

s := Size{li.margins.HNear + li.margins.HFar, li.margins.VNear + li.margins.VFar}
marginsPixels := li.margins.ForDPI(li.ctx.dpi)
s := Size{marginsPixels.HNear + marginsPixels.HFar, marginsPixels.VNear + marginsPixels.VFar}

var maxSecondary int
var maxSecondary Pixel
for _, item := range items {
min := li.MinSizeEffectiveForChild(item.Item)

Expand All @@ -204,21 +205,21 @@ func (li *boxLayoutItem) MinSizeForSize(size Size) Size {
item.Bounds.Width = min.Width

if li.orientation == Horizontal {
maxSecondary = maxi(maxSecondary, item.Bounds.Height)
maxSecondary = maxPixel(maxSecondary, item.Bounds.Height)

s.Width += item.Bounds.Width
} else {
maxSecondary = maxi(maxSecondary, item.Bounds.Width)
maxSecondary = maxPixel(maxSecondary, item.Bounds.Width)

s.Height += item.Bounds.Height
}
}

if li.orientation == Horizontal {
s.Width += (len(items) - 1) * li.spacing
s.Width += Pixel((len(items) - 1) * int(li.spacing))
s.Height += maxSecondary
} else {
s.Height += (len(items) - 1) * li.spacing
s.Height += Pixel((len(items) - 1) * int(li.spacing))
s.Width += maxSecondary
}

Expand Down Expand Up @@ -283,20 +284,24 @@ func boxLayoutFlags(orientation Orientation, children []LayoutItem) LayoutFlags
return flags
}

func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientation Orientation, alignment Alignment2D, bounds Rectangle, margins Margins, spacing int, hwnd2StretchFactor map[win.HWND]int) []LayoutResultItem {
func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientation Orientation, alignment Alignment2D, bounds Rectangle, margins Margins96DPI, spacing Pixel96DPI, hwnd2StretchFactor map[win.HWND]int) []LayoutResultItem {
if len(items) == 0 {
return nil
}

dpi := int(win.GetDpiForWindow(container.Handle()))
marginsPixels := margins.ForDPI(dpi)
spacingPixels := spacing.ForDPI(dpi)

var greedyNonSpacerCount int
var greedySpacerCount int
var stretchFactorsTotal [3]int
stretchFactors := make([]int, len(items))
var minSizesRemaining int
minSizes := make([]int, len(items))
maxSizes := make([]int, len(items))
sizes := make([]int, len(items))
prefSizes2 := make([]int, len(items))
var minSizesRemaining Pixel
minSizes := make([]Pixel, len(items))
maxSizes := make([]Pixel, len(items))
sizes := make([]Pixel, len(items))
prefSizes2 := make([]Pixel, len(items))
growable2 := make([]bool, len(items))
sortedItemInfo := boxLayoutItemInfoList(make([]boxLayoutItemInfo, len(items)))

Expand Down Expand Up @@ -339,7 +344,7 @@ func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientati
growable2[i] = flags&GrowableHorz > 0

if hfw, ok := item.(HeightForWidther); ok && hfw.HasHeightForWidth() {
minSizes[i] = hfw.HeightForWidth(bounds.Width - margins.HNear - margins.HFar)
minSizes[i] = hfw.HeightForWidth(bounds.Width - marginsPixels.HNear - marginsPixels.HFar)
} else {
minSizes[i] = container.MinSizeEffectiveForChild(item).Height
}
Expand Down Expand Up @@ -382,20 +387,20 @@ func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientati

sort.Stable(sortedItemInfo)

var start1, start2, space1, space2 int
var start1, start2, space1, space2 Pixel
if orientation == Horizontal {
start1 = bounds.X + margins.HNear
start2 = bounds.Y + margins.VNear
space1 = bounds.Width - margins.HNear - margins.HFar
space2 = bounds.Height - margins.VNear - margins.VFar
start1 = bounds.X + marginsPixels.HNear
start2 = bounds.Y + marginsPixels.VNear
space1 = bounds.Width - marginsPixels.HNear - marginsPixels.HFar
space2 = bounds.Height - marginsPixels.VNear - marginsPixels.VFar
} else {
start1 = bounds.Y + margins.VNear
start2 = bounds.X + margins.HNear
space1 = bounds.Height - margins.VNear - margins.VFar
space2 = bounds.Width - margins.HNear - margins.HFar
start1 = bounds.Y + marginsPixels.VNear
start2 = bounds.X + marginsPixels.HNear
space1 = bounds.Height - marginsPixels.VNear - marginsPixels.VFar
space2 = bounds.Width - marginsPixels.HNear - marginsPixels.HFar
}

spacingRemaining := spacing * (len(items) - 1)
spacingRemaining := Pixel(int(spacing) * (len(items) - 1))

offsets := [3]int{0, greedyNonSpacerCount, greedyNonSpacerCount + greedySpacerCount}
counts := [3]int{greedyNonSpacerCount, greedySpacerCount, len(items) - greedyNonSpacerCount - greedySpacerCount}
Expand All @@ -414,7 +419,7 @@ func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientati

if min < max {
excessSpace := float64(space1 - minSizesRemaining - spacingRemaining)
size += int(excessSpace * float64(stretch) / float64(stretchFactorsRemaining))
size += Pixel(excessSpace * float64(stretch) / float64(stretchFactorsRemaining))
if size < min {
size = min
} else if size > max {
Expand All @@ -426,21 +431,21 @@ func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientati

minSizesRemaining -= min
stretchFactorsRemaining -= stretch
space1 -= (size + spacing)
spacingRemaining -= spacing
space1 -= (size + spacingPixels)
spacingRemaining -= spacingPixels
}
}

results := make([]LayoutResultItem, 0, len(items))

excessTotal := space1 - minSizesRemaining - spacingRemaining
excessShare := excessTotal / len(items)
halfExcessShare := excessTotal / (len(items) * 2)
excessShare := Pixel(int(excessTotal) / len(items))
halfExcessShare := Pixel(int(excessTotal) / (len(items) * 2))
p1 := start1
for i, item := range items {
s1 := sizes[i]

var s2 int
var s2 Pixel
if hfw, ok := item.(HeightForWidther); ok && orientation == Horizontal && hfw.HasHeightForWidth() {
s2 = hfw.HeightForWidth(s1)
} else if growable2[i] {
Expand All @@ -454,7 +459,7 @@ func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientati
align = alignment
}

var x, y, w, h, p2 int
var x, y, w, h, p2 Pixel
if orientation == Horizontal {
switch align {
case AlignHNearVNear, AlignHNearVCenter, AlignHNearVFar:
Expand Down Expand Up @@ -530,7 +535,7 @@ func boxLayoutItems(container ContainerLayoutItem, items []LayoutItem, orientati
}
}

p1 += s1 + spacing
p1 += s1 + spacingPixels

results = append(results, LayoutResultItem{Item: item, Bounds: Rectangle{X: x, Y: y, Width: w, Height: h}})
}
Expand Down
6 changes: 3 additions & 3 deletions brush.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ const (

type Brush interface {
Dispose()
handle() win.HBRUSH
logbrush() *win.LOGBRUSH
handle() win.HBRUSH // TODO: BitmapBrush is DPI-specific: handle() => handleForDPI()
logbrush() *win.LOGBRUSH // TODO: BitmapBrush is DPI-specific: logbrush() => logbrushForDPI()
attachWindow(wb *WindowBase)
detachWindow(wb *WindowBase)
simple() bool
Expand Down Expand Up @@ -384,7 +384,7 @@ func NewGradientBrush(vertexes []GradientVertex, triangles []GradientTriangle) (
func newGradientBrush(vertexes []GradientVertex, triangles []GradientTriangle, orientation gradientOrientation) (*GradientBrush, error) {
var size Size
for _, v := range vertexes {
size = maxSize(size, Size{int(v.X), int(v.Y)})
size = maxSize(size, Size{Pixel(v.X), Pixel(v.Y)})
}

gb := &GradientBrush{vertexes: vertexes, triangles: triangles, orientation: orientation, absolute: size.Width > 1 || size.Height > 1}
Expand Down
2 changes: 1 addition & 1 deletion button.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ func (b *Button) idealSize() Size {

b.SendMessage(win.BCM_GETIDEALSIZE, 0, uintptr(unsafe.Pointer(&s)))

return maxSize(Size{int(s.CX), int(s.CY)}, b.dialogBaseUnitsToPixels(Size{50, 14}))
return maxSize(sizeFromSIZE(s), b.dialogBaseUnitsToPixels(SizeDBU{50, 14}))
}

func (b *Button) CreateLayoutItem(ctx *LayoutContext) LayoutItem {
Expand Down
Loading

0 comments on commit 20effb6

Please sign in to comment.