blob: 117fdd6629f28ba329c261145dc90375ff4cef87 [file] [log] [blame]
 // Copyright 2020 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Package coords keeps coordinates-related structs and their utilities for the // UI system. package coords import ( "fmt" "math" ) // Point represents a location. type Point struct { X int `json:"x"` Y int `json:"y"` } // NewPoint creates a new Point instance for given x,y coordinates. func NewPoint(x, y int) Point { return Point{X: x, Y: y} } // String returns the string representation of Point. func (p Point) String() string { return fmt.Sprintf("(%d, %d)", p.X, p.Y) } // Equals returns true if the point equals another one. func (p Point) Equals(p2 Point) bool { return p.X == p2.X && p.Y == p2.Y } // Add returns the addition of two Points. func (p Point) Add(p2 Point) Point { return Point{p.X + p2.X, p.Y + p2.Y} } // Sub returns the subtraction of two Points. func (p Point) Sub(p2 Point) Point { return Point{p.X - p2.X, p.Y - p2.Y} } // Size represents a size of a region. type Size struct { Width int `json:"width"` Height int `json:"height"` } // NewSize creates a new Size instance for given width,height. func NewSize(w, h int) Size { return Size{Width: w, Height: h} } // String returns the string representation of Size. func (s Size) String() string { return fmt.Sprintf("(%d x %d)", s.Width, s.Height) } // Rect represents a rectangular region. type Rect struct { Left int `json:"left"` Top int `json:"top"` Width int `json:"width"` Height int `json:"height"` } // NewRect creates a new Rect instance for given x, y width, and height. func NewRect(x, y, w, h int) Rect { return Rect{Left: x, Top: y, Width: w, Height: h} } // NewRectLTRB creates a new rect instance for left, top, right, and bottom // coordinates. func NewRectLTRB(l, t, r, b int) Rect { return Rect{Left: l, Top: t, Width: r - l, Height: b - t} } // String returns the string representation of Rect. func (r Rect) String() string { return fmt.Sprintf("(%d, %d) - (%d x %d)", r.Left, r.Top, r.Width, r.Height) } // Right returns the x-value of the right edge of the rectangle. func (r Rect) Right() int { return r.Left + r.Width } // Bottom returns the y-value of the bottom edge of the rectangle. func (r Rect) Bottom() int { return r.Top + r.Height } // CenterX returns the x-value of the center point of the rectangle. func (r Rect) CenterX() int { return r.Left + r.Width/2 } // CenterY returns the y-value of the center point of the rectangle. func (r Rect) CenterY() int { return r.Top + r.Height/2 } // TopLeft returns the location of the top left of the rectangle. func (r Rect) TopLeft() Point { return Point{X: r.Left, Y: r.Top} } // TopRight returns the location of the top right of the rectangle. func (r Rect) TopRight() Point { return Point{X: r.Left + r.Width, Y: r.Top} } // BottomLeft returns the location of the bottom left of the rectangle. func (r Rect) BottomLeft() Point { return Point{X: r.Left, Y: r.Top + r.Height} } // BottomRight returns the location of the bottom right of the rectangle. func (r Rect) BottomRight() Point { return Point{X: r.Left + r.Width, Y: r.Top + r.Height} } // BottomCenter returns the center location of the bottom edge of the rectangle. func (r Rect) BottomCenter() Point { return Point{X: r.Left + r.Width/2, Y: r.Top + r.Height} } // CenterPoint returns the location of the center of the rectangle. func (r Rect) CenterPoint() Point { return Point{X: r.Left + r.Width/2, Y: r.Top + r.Height/2} } // Empty returns true if the r is zero-value. func (r Rect) Empty() bool { return r == Rect{} } // Size returns the size of the rect. func (r Rect) Size() Size { return Size{Width: r.Width, Height: r.Height} } // Contains returns whether `other` is a rectangle contained within r. // A rectangle is considered to contain itself. func (r Rect) Contains(other Rect) bool { return r.Left <= other.Left && r.Top <= other.Top && r.Bottom() >= other.Bottom() && r.Right() >= other.Right() } func min(x, y int) int { if x < y { return x } return y } func max(x, y int) int { if x < y { return y } return x } // Intersection returns the intersection of two rectangles, or an empty // rectangle if they don't intersect. func (r Rect) Intersection(other Rect) Rect { res := NewRectLTRB( max(r.Left, other.Left), max(r.Top, other.Top), min(r.Right(), other.Right()), min(r.Bottom(), other.Bottom())) if res.Width < 0 || res.Height < 0 { return Rect{} } return res } // WithInset returns a new Rect inset by the given amounts. If insetting would cause the rectangle to // have negative area, instead an empty rectangle with the same CenterPoint is returned. // Note that dw and dh may be negative to outset a rectangle. func (r Rect) WithInset(dw, dh int) Rect { dw2 := dw * 2 if dw2 > r.Width { dw2 = r.Width } dh2 := dh * 2 if dh2 > r.Height { dh2 = r.Height } return NewRect(r.Left+dw2/2, r.Top+dh2/2, r.Width-dw2, r.Height-dh2) } // WithOffset returns a new Rect offset by the given amounts. func (r Rect) WithOffset(dl, dt int) Rect { return NewRect(r.Left+dl, r.Top+dt, r.Width, r.Height) } // convertBounds is used by ConvertBoundsFromDPToPX and ConvertBoundsFromPXToDP. func convertBounds(bounds Rect, factor float64) Rect { return Rect{ Left: int(math.Round(float64(bounds.Left) * factor)), Top: int(math.Round(float64(bounds.Top) * factor)), Width: int(math.Round(float64(bounds.Width) * factor)), Height: int(math.Round(float64(bounds.Height) * factor))} } // ConvertBoundsFromDPToPX converts the given bounds in dips to pixels based on the given device // scale factor. The converted values of Left, Top, Width, and Height are rounded. func ConvertBoundsFromDPToPX(bounds Rect, dsf float64) Rect { return convertBounds(bounds, dsf) } // ConvertBoundsFromPXToDP converts the given bounds in pixels to dips based on the given device // scale factor. The converted values of Left, Top, Width, and Height are rounded. func ConvertBoundsFromPXToDP(bounds Rect, dsf float64) Rect { return convertBounds(bounds, 1.0/dsf) }