Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a select component #41

Merged
merged 1 commit into from
Aug 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
)
Loading