Skip to content

Commit

Permalink
Merge pull request #41 from JD557/select
Browse files Browse the repository at this point in the history
Add a select component
  • Loading branch information
JD557 committed Aug 12, 2023
2 parents cbc15af + 12bb474 commit 68174cf
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 1 deletion.
32 changes: 32 additions & 0 deletions core/src/main/scala/eu/joaocosta/interim/api/Components.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package eu.joaocosta.interim.api

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

Expand Down Expand Up @@ -71,6 +72,37 @@ trait Components:
else (skin.renderButton(area, label, itemStatus))
value.get

/** Select box component. Returns the index value currently selected.
*
* The returned value is returned inside an Either.
* - Left means the select box is open
* - Right means the select box is closed
*
* @param labels text labels for each value
*/
final def select(
id: ItemId,
area: Rect,
labels: Vector[String],
skin: SelectSkin = SelectSkin.default()
): ComponentWithValue[Either[Int, Int]] =
new ComponentWithValue[Either[Int, Int]]:
def applyRef(value: Ref[Either[Int, Int]]): Component[Either[Int, Int]] =
val selectBoxArea = skin.selectBoxArea(area)
val itemStatus = UiContext.registerItem(id, area)
val selectedValue = value.get.merge
if (itemStatus.keyboardFocus) value := Left(selectedValue)
val isOpen = value.get.isLeft
skin.renderSelectBox(area, selectedValue, labels, itemStatus)
if (isOpen)
if (!itemStatus.keyboardFocus) value := Right(selectedValue)
labels.zipWithIndex.foreach: (label, idx) =>
val selectOptionArea = skin.selectOptionArea(area, idx)
val optionStatus = UiContext.registerItem(id |> idx, selectOptionArea)
skin.renderSelectOption(area, idx, labels, optionStatus)
if (optionStatus.active) value := Right(idx)
value.get

/** Slider component. Returns the current position of the slider, between min and max.
*
* @param min minimum value for this slider
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/eu/joaocosta/interim/api/Panels.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package eu.joaocosta.interim.api

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import eu.joaocosta.interim.Color
object ColorScheme:
val white = Color(246, 247, 251)
val lightGray = Color(177, 186, 177)
val pureGray = Color(127, 127, 127)
val darkGray = Color(77, 77, 77)
val black = Color(23, 21, 23)

Expand Down
89 changes: 89 additions & 0 deletions core/src/main/scala/eu/joaocosta/interim/skins/SelectSkin.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package eu.joaocosta.interim.skins

import eu.joaocosta.interim.*
import eu.joaocosta.interim.api.Primitives.*

trait SelectSkin:
def selectBoxArea(area: Rect): Rect
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,
inactiveColor: Color,
hotColor: Color,
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 =
val selectBoxArea = this.selectBoxArea(area)
val selectedLabel = labels.applyOrElse(value, _ => "")
itemStatus match
case UiContext.ItemStatus(_, _, true) | UiContext.ItemStatus(_, true, _) =>
rectangle(selectBoxArea, activeColor)
case UiContext.ItemStatus(true, _, _) =>
rectangle(selectBoxArea, hotColor)
case UiContext.ItemStatus(_, _, _) =>
rectangle(selectBoxArea, inactiveColor)
text(
selectBoxArea.shrink(border),
textColor,
selectedLabel,
font,
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 =
val selectOptionArea = this.selectOptionArea(area, value)
val optionLabel = labels.applyOrElse(value, _ => "")
onTop:
itemStatus match
case UiContext.ItemStatus(_, _, true) | UiContext.ItemStatus(_, true, _) =>
rectangle(selectOptionArea, activeColor)
case UiContext.ItemStatus(true, _, _) =>
rectangle(selectOptionArea, hotColor)
case UiContext.ItemStatus(_, _, _) =>
rectangle(selectOptionArea, inactiveColor)
text(
selectOptionArea.shrink(border),
textColor,
optionLabel,
font,
TextLayout.HorizontalAlignment.Left,
TextLayout.VerticalAlignment.Center
)

val lightDefault: Default = Default(
border = 2,
font = Font.default,
inactiveColor = ColorScheme.lightGray,
hotColor = ColorScheme.pureGray,
activeColor = ColorScheme.lightPrimaryHighlight,
textColor = ColorScheme.black
)

val darkDefault: Default = Default(
border = 2,
font = Font.default,
inactiveColor = ColorScheme.darkGray,
hotColor = ColorScheme.pureGray,
activeColor = ColorScheme.darkPrimaryHighlight,
textColor = ColorScheme.white
)

0 comments on commit 68174cf

Please sign in to comment.