Skip to content

Commit

Permalink
Move LayoutAllocators to the layouts package
Browse files Browse the repository at this point in the history
  • Loading branch information
JD557 committed May 4, 2024
1 parent 9436e0c commit 5ac170c
Show file tree
Hide file tree
Showing 14 changed files with 181 additions and 175 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package eu.joaocosta.interim

import eu.joaocosta.interim.{Font, HorizontalAlignment, Rect, TextLayout, VerticalAlignment}

/** A layout allocator is a side-effectful function that, given a size (width or height) tries to allocate
* a new area.
*
* Note that calls to this function are side effectful, as each call reserves an area.
*/
trait LayoutAllocator:
def area: Rect

def allocate(width: Int, height: Int): Rect
def allocate(text: String, font: Font, paddingW: Int = 0, paddingH: Int = 0): Rect =
val textArea =
TextLayout.computeArea(area.resize(-2 * paddingW, -2 * paddingH), text, font)
allocate(textArea.w + 2 * paddingW, textArea.h + 2 * paddingH)

def fill(): Rect = allocate(Int.MaxValue, Int.MaxValue)

object LayoutAllocator:
trait RowAllocator extends LayoutAllocator:
def nextRow(height: Int): Rect
def allocate(width: Int, height: Int): Rect = nextRow(height)

trait ColumnAllocator extends LayoutAllocator:
def nextColumn(width: Int): Rect
def allocate(width: Int, height: Int): Rect = nextColumn(width)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package eu.joaocosta.interim.api

import eu.joaocosta.interim.api.LayoutAllocator._
import eu.joaocosta.interim.{HorizontalAlignment, InputState, Rect, UiContext, VerticalAlignment}
import eu.joaocosta.interim._
import eu.joaocosta.interim.layouts._

/** Objects containing all default layouts.
*
Expand Down Expand Up @@ -75,7 +75,7 @@ trait Layouts:
padding: Int,
alignment: VerticalAlignment.Top.type | VerticalAlignment.Bottom.type = VerticalAlignment.Top
)(body: DynamicRowAllocator ?=> T): T =
val allocator = new LayoutAllocator.DynamicRowAllocator(area, padding, alignment)
val allocator = new DynamicRowAllocator(area, padding, alignment)
body(using allocator)

/** Lays out the components in a sequence of columns of different sizes, separated by a padding.
Expand All @@ -88,7 +88,7 @@ trait Layouts:
padding: Int,
alignment: HorizontalAlignment.Left.type | HorizontalAlignment.Right.type = HorizontalAlignment.Left
)(body: DynamicColumnAllocator ?=> T): T =
val allocator = new LayoutAllocator.DynamicColumnAllocator(area, padding, alignment)
val allocator = new DynamicColumnAllocator(area, padding, alignment)
body(using allocator)

/** Handle mouse events inside a specified area.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package eu.joaocosta.interim.api

import eu.joaocosta.interim.{Color, Font, HorizontalAlignment, Rect, RenderOp, UiContext, VerticalAlignment}
import eu.joaocosta.interim._

/** Object containing the default primitives.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package eu.joaocosta.interim.layouts

import eu.joaocosta.interim._

final class DynamicColumnAllocator(
val area: Rect,
padding: Int,
alignment: HorizontalAlignment.Left.type | HorizontalAlignment.Right.type
) extends LayoutAllocator.ColumnAllocator
with (Int => Rect):
private var currentX = area.x
private var currentW = area.w
private val dirMod = if (alignment == HorizontalAlignment.Left) 1 else -1

def nextColumn(width: Int): Rect =
val absWidth = math.abs(width).toInt
if (absWidth == 0 || currentW <= 0) // Empty
area.copy(x = currentX, w = 0)
else if (absWidth >= currentW) // Fill remaining area
val areaX = currentX
val areaW = currentW
currentX = area.w
currentW = 0
area.copy(x = areaX, w = areaW)
else if (dirMod * width >= 0) // Fill from the left
val areaX = currentX
currentX += absWidth + padding
currentW -= absWidth + padding
area.copy(x = areaX, w = absWidth)
else // Fill from the right
val areaX = currentX + currentW - absWidth
currentW -= absWidth + padding
area.copy(x = areaX, w = absWidth)

def apply(height: Int) = nextColumn(height)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package eu.joaocosta.interim.layouts

import eu.joaocosta.interim._

final class DynamicRowAllocator(
val area: Rect,
padding: Int,
alignment: VerticalAlignment.Top.type | VerticalAlignment.Bottom.type
) extends LayoutAllocator.RowAllocator
with (Int => Rect):
private var currentY = area.y
private var currentH = area.h
private val dirMod = if (alignment == VerticalAlignment.Top) 1 else -1

def nextRow(height: Int) =
val absHeight = math.abs(height).toInt
if (absHeight == 0 || currentH <= 0) // Empty
area.copy(y = currentY, h = 0)
else if (absHeight >= currentH) // Fill remaining area
val areaY = currentY
val areaH = currentH
currentY = area.h
currentH = 0
area.copy(y = areaY, h = areaH)
else if (dirMod * height >= 0) // Fill from the top
val areaY = currentY
currentY += absHeight + padding
currentH -= absHeight + padding
area.copy(y = areaY, h = absHeight)
else // Fill from the bottom
val areaY = currentY + currentH - absHeight
currentH -= absHeight + padding
area.copy(y = areaY, h = absHeight)

def apply(height: Int) = nextRow(height)
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package eu.joaocosta.interim.layouts

import eu.joaocosta.interim._

final class StaticColumnAllocator(
val area: Rect,
padding: Int,
numColumns: Int,
alignment: HorizontalAlignment.Left.type | HorizontalAlignment.Right.type
) extends LayoutAllocator.ColumnAllocator
with IndexedSeq[Rect]:
val cells: IndexedSeq[Rect] =
if (numColumns == 0) Vector.empty
else
val columnSize = (area.w - (numColumns - 1) * padding) / numColumns.toDouble
val intColumnSize = columnSize.toInt
val baseCells = for
column <- (0 until numColumns)
dx = (column * (columnSize + padding)).toInt
yield Rect(area.x + dx, area.y, intColumnSize, area.h)
if (alignment == HorizontalAlignment.Left) baseCells
else baseCells.reverse

def apply(i: Int): Rect = cells(i)
val length = cells.length

private val cellsIterator = cells.iterator

def nextColumn(): Rect =
if (!cellsIterator.hasNext) area.copy(w = 0, h = 0)
else cellsIterator.next()

def nextColumn(width: Int): Rect =
if (!cellsIterator.hasNext) area.copy(w = 0, h = 0)
else
var acc = cellsIterator.next()
while (acc.w < width && cellsIterator.hasNext)
acc = acc ++ cellsIterator.next()
acc
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package eu.joaocosta.interim.layouts

import eu.joaocosta.interim._

final class StaticRowAllocator(
val area: Rect,
padding: Int,
numRows: Int,
alignment: VerticalAlignment.Top.type | VerticalAlignment.Bottom.type
) extends LayoutAllocator.RowAllocator
with IndexedSeq[Rect]:
val cells: IndexedSeq[Rect] =
if (numRows == 0) Vector.empty
else
val rowSize = (area.h - (numRows - 1) * padding) / numRows.toDouble
val intRowSize = rowSize.toInt
val baseCells = for
row <- (0 until numRows)
dy = (row * (rowSize + padding)).toInt
yield Rect(area.x, area.y + dy, area.w, intRowSize)
if (alignment == VerticalAlignment.Top) baseCells
else baseCells.reverse

def apply(i: Int): Rect = cells(i)
val length = cells.length

private val cellsIterator = cells.iterator

def nextRow(): Rect =
if (!cellsIterator.hasNext) area.copy(w = 0, h = 0)
else cellsIterator.next()

def nextRow(height: Int): Rect =
if (!cellsIterator.hasNext) area.copy(w = 0, h = 0)
else
var acc = cellsIterator.next()
while (acc.h < height && cellsIterator.hasNext)
acc = acc ++ cellsIterator.next()
acc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package eu.joaocosta.interim.skins

import eu.joaocosta.interim.TextLayout._
import eu.joaocosta.interim._
import eu.joaocosta.interim.api.LayoutAllocator
import eu.joaocosta.interim.api.Primitives._

trait ButtonSkin:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package eu.joaocosta.interim.skins

import eu.joaocosta.interim._
import eu.joaocosta.interim.api.LayoutAllocator
import eu.joaocosta.interim.api.Primitives._

trait CheckboxSkin:
Expand Down
Loading

0 comments on commit 5ac170c

Please sign in to comment.