Commit 8f5c5856 authored by h2b's avatar h2b

Layout package reworked.

parent 2d74cdb5
......@@ -28,25 +28,29 @@ import de.h2b.scala.lib.simgraf.Pixel
* @since 1.1.0
* @author h2b
*/
class Cell private (val width: Int, val height: Int) {
class Cell protected (val width: Int, val height: Int, val origin: Pixel) extends Equals {
import Cell.HorizontalOrientation._
import Cell.VerticalOrientation._
/**
* Returns the top-left pixel position of a rectangular area with specified
* dimensions and orientation within this cell.
* A copy of this cell at a new origin.
*/
def at (origin: Pixel): Cell = new Cell(width, height, origin)
/**
* Returns a new cell with specified dimensions and orientation within this cell.
*
* @note If the area to be fitted in does not fit into this cell the resulting
* pixel coordinates might be negative.
* @note If the cell to be fitted in does not fit into this cell the resulting
* cell's origin might be negative.
*
* @param w the width of of the area to be fitted in
* @param h the height of of the area to be fitted in
* @param o the orientation of of the area to be fitted in within this cell
* @param w the width of of the cell to be fitted in
* @param h the height of of the cell to be fitted in
* @param o the orientation of of the cell to be fitted in within this cell
* (defaults to centring both dimensions)
* @return the resulting top-left pixel position
* @return the resulting new cell
*/
def fit (w: Int, h: Int, o: Cell.Orientation = Cell.defaultOrientation): Pixel = {
def fit (w: Int, h: Int, o: Cell.Orientation = Cell.DefaultOrientation): Cell = {
val x = o.horizontal match {
case Left 0
case HCenter (width -w)/2
......@@ -57,7 +61,27 @@ class Cell private (val width: Int, val height: Int) {
case VCenter (height-h)/2
case Bottom height-h
}
Pixel(x, y)
new Cell(w, h, Pixel(x, y))
}
override def toString = s"Cell($width, $height, $origin)"
def canEqual (other: Any) = {
other.isInstanceOf[Cell]
}
override def equals(other: Any) = {
other match {
case that: Cell =>
that.canEqual(this) && width == that.width && height == that.height && origin == that.origin
case _ =>
false
}
}
override def hashCode() = {
val prime = 41
prime * (prime * (prime + width.hashCode) + height.hashCode) + origin.hashCode
}
}
......@@ -89,8 +113,17 @@ object Cell {
}
/** An orientation centred in both directions. */
val defaultOrientation = Orientation(HCenter, VCenter)
final val DefaultOrientation = Orientation(HCenter, VCenter)
/** `(0, 0)`. */
final val DefaultOrigin = Pixel(0, 0)
def apply (width: Int, height: Int) = new Cell(width, height)
/**
* A new cell with given width, height and origin.
*
* @param origin the upper-left corner of this cell, defaults to `(0, 0)`
*/
def apply (width: Int, height: Int, origin: Pixel = DefaultOrigin) =
new Cell(width, height, origin)
}
......@@ -47,13 +47,15 @@ import Floating._
* @since 1.1.0
* @author h2b
*/
class GridLayout private (val rows: Int, val cols: Int, val cell: Cell, val floating: Floating,
p0: Pixel) extends Iterable[Pixel] {
class GridLayout private (val rows: Int, val cols: Int, val cell: Cell,
val floating: Floating) extends Cell(cols*cell.width, rows*cell.height, cell.origin) with
Iterable[Cell] {
/**
* A copy of this grid layout at a new origin.
*/
def at (origin: Pixel): GridLayout = new GridLayout(rows, cols, cell, floating, origin)
override def at (origin: Pixel): GridLayout =
new GridLayout(rows, cols, cell at origin, floating)
def iterator = floating match {
case Horizontal floatingIterator(rows, cols, (i, j) (i, j))
......@@ -61,45 +63,45 @@ class GridLayout private (val rows: Int, val cols: Int, val cell: Cell, val floa
}
private def floatingIterator (dim1: Int, dim2: Int, index: (Int, Int) (Int, Int)) =
new Iterator[Pixel] {
new Iterator[Cell] {
private var i, j = 0
def hasNext = i < dim1
def next = {
if (!hasNext) throw new NoSuchElementException("iterator overflow")
val (k, l) = index(i, j)
val result = p0 + Pixel(l*cell.width, k*cell.height)
val result = cell at (cell.origin + Pixel(l*cell.width, k*cell.height))
j += 1
if (j == dim2) { i += 1; j = 0 }
result
}
}
override def toString = s"GridLayout($rows, $cols, $cell, $floating)"
}
object GridLayout {
/** Floating from left to right. */
val defaultFloating = Floating.Horizontal
/** Zero point. */
val defaultOrigin = Pixel(0, 0)
final val DefaultFloating = Floating.Horizontal
/**
* Constructs a new grid layout of the specified number of rows and columns
* using cells of dimensions of the given cell.
* using cells of dimensions of the given sample cell. Also, the sample
* cell's origin is the origin of the resulting layout.
*
* @param floating instructs the iterator to visit the cells either in
* horizontal (first left to right, then top to bottom) or vertical (vice
* versa) order (defaults to horizontal)
*/
def apply (rows: Int, cols: Int, cell: Cell, floating: Floating = defaultFloating,
origin: Pixel = defaultOrigin): GridLayout =
new GridLayout(rows, cols, cell, floating, origin)
def apply (rows: Int, cols: Int, cell: Cell, floating: Floating = DefaultFloating): GridLayout =
new GridLayout(rows, cols, cell, floating)
/**
* Constructs a new grid layout of the specified number of rows and columns
* on a rectangular area of specified width and height.
*
* @param origin the upper-left corner of this layout, defaults to `(0, 0)`
* @param floating instructs the iterator to visit the cells either in
* horizontal (first left to right, then top to bottom) or vertical (vice
* versa) order (defaults to horizontal)
......@@ -107,23 +109,24 @@ object GridLayout {
* @throws ArithmeticException if `rows` or `cols` is zero
*/
def onRectangle (rows: Int, cols: Int, width: Int, height: Int,
floating: Floating = defaultFloating, origin: Pixel = defaultOrigin): GridLayout = {
val cell = Cell(width/cols, height/rows)
new GridLayout(rows, cols, cell, floating, origin)
floating: Floating = DefaultFloating, origin: Pixel = Cell.DefaultOrigin): GridLayout = {
val cell = Cell(width/cols, height/rows, origin)
new GridLayout(rows, cols, cell, floating)
}
/**
* Constructs a new grid layout of the specified number of rows and columns
* on the whole screen.
*
* @param origin the upper-left corner of this layout, defaults to `(0, 0)`
* @param floating instructs the iterator to visit the cells either in
* horizontal (first left to right, then top to bottom) or vertical (vice
* versa) order (defaults to horizontal)
*
* @throws ArithmeticException if `rows` or `cols` is zero
*/
def onScreen (rows: Int, cols: Int, floating: Floating = defaultFloating,
origin: Pixel = defaultOrigin): GridLayout = {
def onScreen (rows: Int, cols: Int, floating: Floating = DefaultFloating,
origin: Pixel = Cell.DefaultOrigin): GridLayout = {
onRectangle(rows, cols, Screen.width, Screen.height, floating, origin)
}
......
......@@ -31,14 +31,18 @@ class CellTest extends FunSuite {
val cell = Cell(1000, 1000)
test("at") {
assertResult(Cell(1000, 1000, Pixel(100, 200)))(cell at Pixel(100, 200))
}
test("fitting default orientation") {
assertResult(Pixel(450, 450))(cell.fit(100, 100))
assertResult(Cell(100, 100, Pixel(450, 450)))(cell.fit(100, 100))
}
test("fitting arbitrary orientations") {
assertResult(Pixel(0, 0))(cell.fit(100, 100, Cell.Orientation(Left, Top)))
assertResult(Pixel(450, 450))(cell.fit(100, 100, Cell.Orientation(HCenter, VCenter)))
assertResult(Pixel(900, 900))(cell.fit(100, 100, Cell.Orientation(Right, Bottom)))
assertResult(Cell(100, 100, Pixel(0, 0)))(cell.fit(100, 100, Cell.Orientation(Left, Top)))
assertResult(Cell(100, 100, Pixel(450, 450)))(cell.fit(100, 100, Cell.Orientation(HCenter, VCenter)))
assertResult(Cell(100, 100, Pixel(900, 900)))(cell.fit(100, 100, Cell.Orientation(Right, Bottom)))
}
}
......@@ -30,13 +30,20 @@ class GridLayoutTest extends FunSuite {
val hlayout = GridLayout.onRectangle(2, 3, 300, 200, origin=Pixel(50, 150))
val vlayout = GridLayout.onRectangle(2, 3, 300, 200, floating=Vertical) at Pixel(50, 150)
val cell = Cell(100, 100)
test("at") {
val actual = hlayout at Pixel(100, 200)
assertResult(Pixel(100, 200))(actual.origin)
}
test("horizontal iterator") {
val expected = Seq(
Pixel(50,150), Pixel(150,150), Pixel(250,150),
Pixel(50,250), Pixel(150,250), Pixel(250,250))
var i = 0
for (p hlayout) {
assertResult(expected(i))(p)
assertResult(cell at expected(i))(p)
i += 1
}
}
......@@ -48,7 +55,7 @@ class GridLayoutTest extends FunSuite {
Pixel(250,150), Pixel(250,250))
var i = 0
for (p vlayout) {
assertResult(expected(i))(p)
assertResult(cell at expected(i))(p)
i += 1
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment