Skip to content

Commit

Permalink
Merge pull request #44 from JD557/cleanup
Browse files Browse the repository at this point in the history
Code cleanup
  • Loading branch information
JD557 authored Aug 13, 2023
2 parents 0c038e4 + 3b724d3 commit 0010dd8
Show file tree
Hide file tree
Showing 27 changed files with 91 additions and 71 deletions.
1 change: 1 addition & 0 deletions core/src/main/scala/eu/joaocosta/interim/InputState.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import scala.annotation.tailrec
* A `\u0008` character is interpreted as a backspace.
*/
final case class InputState(mouseX: Int, mouseY: Int, mouseDown: Boolean, keyboardInput: String):

/** Appends the current keyboard input to an already existing string.
* A `\u0008` character in the input is interpreted as a backspace.
*/
Expand Down
1 change: 1 addition & 0 deletions core/src/main/scala/eu/joaocosta/interim/InterIm.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import eu.joaocosta.interim.TextLayout.*
* import the DSL and explicitly use the InterIm prefix (e.g. `IterIm.text` instead of `text`)
*/
object InterIm extends api.Primitives with api.Layouts with api.Components with api.Constants with api.Panels:

/** Wraps the UI interactions. All API calls should happen inside the body (run parameter).
*
* This method takes an input state and a UI context and mutates the UI context accordingly.
Expand Down
31 changes: 15 additions & 16 deletions core/src/main/scala/eu/joaocosta/interim/ItemId.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,19 @@ import scala.annotation.targetName
*/
type ItemId = (Int | String) | List[(Int | String)]

object ItemId:
/** Helper method to convert an ItemId into a List
*/
extension (itemId: ItemId)
def toIdList: List[(Int | String)] =
itemId match {
case int: Int => List(int)
case str: String => List(str)
case list: List[(Int | String)] => list
}
/** Helper method to convert an ItemId into a List
*/
extension (itemId: ItemId)
def toIdList: List[(Int | String)] =
itemId match {
case int: Int => List(int)
case str: String => List(str)
case list: List[(Int | String)] => list
}

/** Operator to add a child to an item id. Useful for composite components.
*/
extension (parentId: ItemId)
@targetName("addChild")
def |>(childId: ItemId): ItemId =
parentId.toIdList ++ childId.toIdList
/** Operator to add a child to an item id. Useful for composite components.
*/
extension (parentId: ItemId)
@targetName("addChild")
def |>(childId: ItemId): ItemId =
parentId.toIdList ++ childId.toIdList
6 changes: 3 additions & 3 deletions core/src/main/scala/eu/joaocosta/interim/Rect.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package eu.joaocosta.interim

import scala.annotation.alpha
import scala.annotation.targetName

/** Rectangle abstraction, which represents an area with positive width and height.
*
Expand Down Expand Up @@ -47,7 +47,7 @@ final case class Rect(x: Int, y: Int, w: Int, h: Int):
*
* Gaps between the rectangles will also be considered as part of the final area.
*/
@alpha("merge")
@targetName("merge")
def ++(that: Rect): Rect =
val minX = math.min(this.x1, that.x1)
val maxX = math.max(this.x2, that.x2)
Expand All @@ -57,7 +57,7 @@ final case class Rect(x: Int, y: Int, w: Int, h: Int):

/** Intersects this rectangle with another one.
*/
@alpha("intersect")
@targetName("intersect")
def &(that: Rect): Rect =
val maxX1 = math.max(this.x1, that.x1)
val maxY1 = math.max(this.y1, that.y1)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package eu.joaocosta.interim.api
package eu.joaocosta.interim

import scala.annotation.targetName
import scala.deriving.Mirror
Expand Down Expand Up @@ -53,16 +53,16 @@ object Ref:
refTuple.map([T] => (x: T) => x.asInstanceOf[Ref[_]].value.asInstanceOf[UnRef[T]]).asInstanceOf
mirror.fromTuple(updatedTuple)

/** Wraps this value into a Ref and passes it to a block, returning the final value of the ref.
*
* Useful to set temporary mutable variables.
*/
extension [T](x: T) def asRef(block: Ref[T] => Unit): T = withRef(x)(block)
/** Wraps this value into a Ref and passes it to a block, returning the final value of the ref.
*
* Useful to set temporary mutable variables.
*/
extension [T](x: T) def asRef(block: Ref[T] => Unit): T = Ref.withRef(x)(block)

/** Destructures this value into multiple Refs and passes it to a block, returning the final value of the ref.
*
* Useful to set temporary mutable variables.
*/
extension [T <: Product](x: T)
def asRefs(using mirror: Mirror.ProductOf[T])(block: Tuple.Map[mirror.MirroredElemTypes, Ref] => Unit): T =
withRefs(x)(block)
/** Destructures this value into multiple Refs and passes it to a block, returning the final value of the ref.
*
* Useful to set temporary mutable variables.
*/
extension [T <: Product](x: T)
def asRefs(using mirror: Mirror.ProductOf[T])(block: Tuple.Map[mirror.MirroredElemTypes, Ref] => Unit): T =
Ref.withRefs(x)(block)
1 change: 1 addition & 0 deletions core/src/main/scala/eu/joaocosta/interim/RenderOp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ sealed trait RenderOp {
}

object RenderOp:

/** Operation to draw a rectangle on the screen.
*
* @param area area to render
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/eu/joaocosta/interim/TextLayout.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package eu.joaocosta.interim
import scala.annotation.tailrec

object TextLayout:

enum HorizontalAlignment:
case Left, Center, Right

Expand Down Expand Up @@ -88,5 +89,4 @@ object TextLayout:
if (ops.isEmpty && nextLine == remaining) layout("", dy, textAcc) // Can't fit a single character, end here
else
layout(nextLine, dy + lineHeight, alignH(ops, textOp.textArea.w, textOp.horizontalAlignment) ++ textAcc)

layout(textOp.text, 0, Nil).filter(char => (char.area & textOp.area) == char.area)
13 changes: 6 additions & 7 deletions core/src/main/scala/eu/joaocosta/interim/api/Components.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package eu.joaocosta.interim.api

import eu.joaocosta.interim.ItemId.*
import eu.joaocosta.interim.*
import eu.joaocosta.interim.skins.*

Expand All @@ -14,14 +13,15 @@ trait Components:

type Component[+T] = (inputState: InputState, uiContext: UiContext) ?=> T

trait ComponentWithValue[T] {
trait ComponentWithValue[T]:
def applyRef(value: Ref[T]): Component[T]

def applyValue(value: T): Component[T] =
apply(Ref(value))

inline def apply(value: T | Ref[T]): Component[T] = inline value match
case x: T => applyValue(x)
case x: Ref[T] => applyRef(x)
}

/** Button component. Returns true if it's being clicked, false otherwise.
*
Expand All @@ -46,9 +46,8 @@ trait Components:
val checkboxArea = skin.checkboxArea(area)
val itemStatus = UiContext.registerItem(id, checkboxArea)
skin.renderCheckbox(area, value.get, itemStatus)
if (itemStatus.hot && itemStatus.active && summon[InputState].mouseDown == false)
value.modify(!_).get
else value.get
if (itemStatus.hot && itemStatus.active && summon[InputState].mouseDown == false) value.modify(!_)
value.get

/** Radio button component. Returns value currently selected.
*
Expand All @@ -69,7 +68,7 @@ trait Components:
if (itemStatus.hot && itemStatus.active && summon[InputState].mouseDown == false)
value := buttonValue
if (value.get == buttonValue) skin.renderButton(area, label, itemStatus.copy(hot = true, active = true))
else (skin.renderButton(area, label, itemStatus))
else skin.renderButton(area, label, itemStatus)
value.get

/** Select box component. Returns the index value currently selected inside a PanelState.
Expand Down
7 changes: 3 additions & 4 deletions core/src/main/scala/eu/joaocosta/interim/api/Panels.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package eu.joaocosta.interim.api

import eu.joaocosta.interim.ItemId.*
//import eu.joaocosta.interim.ItemId.*
import eu.joaocosta.interim.*
import eu.joaocosta.interim.skins.*

/** Objects containing all default panels.
*
* Panels are a mix of a component and a layout. They perform rendering operations, but also provide a draw area.
*
* By convention, all panels are of the form `def panel(id, area, params..., skin)(body): (Value, Rect)`.
* By convention, all panels are of the form `def panel(id, area, params..., skin)(body): (Option[Value], PanelState[Rect])`.
* The returned value is the value returned by the body. Panels also return a rect, which is the area
* the panel must be called with in the next frame (e.g. for movable panels).
*
Expand Down Expand Up @@ -40,11 +40,10 @@ trait Panels:
)(
body: Rect => T
): Components.Component[(Option[T], PanelState[Rect])] =
val panelStateRef = area match {
val panelStateRef = area match
case ref: Ref[PanelState[Rect]] => ref
case v: PanelState[Rect] => Ref(v)
case v: Rect => Ref(PanelState.open(v))
}
if (panelStateRef.get.isOpen)
val windowArea = panelStateRef.get.value
UiContext.registerItem(id, windowArea, passive = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import eu.joaocosta.interim.{Color, Font, Rect, RenderOp, UiContext}
object Primitives extends Primitives

trait Primitives:

/** Draws a rectangle filling a the specified area with a color.
*/
final def rectangle(area: Rect, color: Color)(using uiContext: UiContext): Unit =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ trait ButtonSkin:
): Unit

object ButtonSkin extends DefaultSkin:

final case class Default(
shadowDelta: Int,
clickDelta: Int,
Expand All @@ -21,8 +22,10 @@ object ButtonSkin extends DefaultSkin:
hotColor: Color,
activeColor: Color
) extends ButtonSkin:

def buttonArea(area: Rect): Rect =
area.copy(w = area.w - math.max(shadowDelta, clickDelta), h = area.h - math.max(shadowDelta, clickDelta))

def renderButton(area: Rect, label: String, itemStatus: UiContext.ItemStatus)(using
uiContext: UiContext
): Unit =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@ trait CheckboxSkin:
def renderCheckbox(area: Rect, value: Boolean, itemStatus: UiContext.ItemStatus)(using uiContext: UiContext): Unit

object CheckboxSkin extends DefaultSkin:

final case class Default(
padding: Int,
inactiveColor: Color,
hotColor: Color,
activeColor: Color,
checkColor: Color
) extends CheckboxSkin:

def checkboxArea(area: Rect): Rect =
val smallSide = math.min(area.w, area.h)
area.copy(w = smallSide, h = smallSide)

def renderCheckbox(area: Rect, value: Boolean, itemStatus: UiContext.ItemStatus)(using uiContext: UiContext): Unit =
val checkboxArea = this.checkboxArea(area)
itemStatus match
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ import eu.joaocosta.interim.api.Primitives.*
trait HandleSkin:
def moveHandleArea(area: Rect): Rect
def closeHandleArea(area: Rect): Rect

def renderMoveHandle(area: Rect, value: Rect, itemStatus: UiContext.ItemStatus)(using uiContext: UiContext): Unit
def renderCloseHandle(area: Rect, itemStatus: UiContext.ItemStatus)(using uiContext: UiContext): Unit

object HandleSkin extends DefaultSkin:

final case class Default(
inactiveColor: Color,
hotColor: Color,
activeColor: Color
) extends HandleSkin:

def moveHandleArea(area: Rect): Rect =
val smallSide = math.min(area.w, area.h)
area.copy(w = smallSide, h = smallSide)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ trait SelectSkin:
def renderSelectBox(area: Rect, value: Int, labels: Vector[String], itemStatus: UiContext.ItemStatus)(using
uiContext: UiContext
): Unit

def selectOptionArea(area: Rect, value: Int): Rect
def renderSelectOption(area: Rect, value: Int, labels: Vector[String], itemStatus: UiContext.ItemStatus)(using
uiContext: UiContext
): Unit

object SelectSkin extends DefaultSkin:

final case class Default(
border: Int,
font: Font,
Expand All @@ -22,9 +24,11 @@ object SelectSkin extends DefaultSkin:
activeColor: Color,
textColor: Color
) extends SelectSkin:

// Select box
def selectBoxArea(area: Rect): Rect =
area

def renderSelectBox(area: Rect, value: Int, labels: Vector[String], itemStatus: UiContext.ItemStatus)(using
uiContext: UiContext
): Unit =
Expand All @@ -45,9 +49,11 @@ object SelectSkin extends DefaultSkin:
TextLayout.HorizontalAlignment.Left,
TextLayout.VerticalAlignment.Center
)

// Select option
def selectOptionArea(area: Rect, value: Int): Rect =
area.copy(y = area.y + area.h * (value + 1))

def renderSelectOption(area: Rect, value: Int, labels: Vector[String], itemStatus: UiContext.ItemStatus)(using
uiContext: UiContext
): Unit =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ trait SliderSkin:
): Unit

object SliderSkin extends DefaultSkin:

final case class Default(
padding: Int,
minSliderSize: Int,
Expand All @@ -19,12 +20,14 @@ object SliderSkin extends DefaultSkin:
hotColor: Color,
activeColor: Color
) extends SliderSkin:

def sliderSize(area: Rect, min: Int, max: Int): Int =
val steps = (max - min) + 1
math.max(minSliderSize, math.max(area.w, area.h) / steps)

def sliderArea(area: Rect): Rect =
Rect(area.x + padding, area.y + padding, area.w - 2 * padding, area.h - 2 * padding)

def renderSlider(area: Rect, min: Int, value: Int, max: Int, itemStatus: UiContext.ItemStatus)(using
uiContext: UiContext
): Unit =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ trait TextInputSkin:
def renderTextInput(area: Rect, value: String, itemStatus: UiContext.ItemStatus)(using uiContext: UiContext): Unit

object TextInputSkin extends DefaultSkin:

final case class Default(
border: Int,
font: Font,
Expand All @@ -17,8 +18,10 @@ object TextInputSkin extends DefaultSkin:
textAreaColor: Color,
textColor: Color
) extends TextInputSkin:

def textInputArea(area: Rect): Rect =
area.shrink(border)

def renderTextInput(area: Rect, value: String, itemStatus: UiContext.ItemStatus)(using uiContext: UiContext): Unit =
val textInputArea = this.textInputArea(area)
itemStatus match
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,23 @@ trait WindowSkin:
def renderWindow(area: Rect, title: String)(using uiContext: UiContext): Unit

object WindowSkin extends DefaultSkin:

final case class Default(
font: Font,
textColor: Color,
panelColor: Color,
titleColor: Color
) extends WindowSkin:

def titleArea(area: Rect): Rect =
area.copy(h = font.fontSize * 2)

def titleTextArea(area: Rect): Rect =
area.copy(h = font.fontSize * 2).shrink(font.fontSize / 2)

def panelArea(area: Rect): Rect =
area.copy(y = area.y + font.fontSize * 2, h = area.h - font.fontSize * 2)

def renderWindow(area: Rect, title: String)(using uiContext: UiContext): Unit =
val titleArea = this.titleArea(area)
val panelArea = this.panelArea(area)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package eu.joaocosta.interim
import scala.annotation.tailrec

class InputStateSpec extends munit.FunSuite:

test("appendKeyboardInput should preserve the original string"):
val result = InputState(0, 0, false, "").appendKeyboardInput("test")
assertEquals(result, "test")
Expand Down
1 change: 1 addition & 0 deletions core/src/test/scala/eu/joaocosta/interim/RectSpec.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package eu.joaocosta.interim

class RectSpec extends munit.FunSuite:

test("isMouseOver detects collisions with the mouse"):
val rect = Rect(10, 10, 10, 10)
assertEquals(rect.isMouseOver(using InputState(0, 0, false, "")), false)
Expand Down
Loading

0 comments on commit 0010dd8

Please sign in to comment.