Add IconButton.onClicked for regular buttons

This commit is contained in:
Fingercomp 2025-08-12 02:58:20 +03:00
parent 47ea0e7d9a
commit 055671abc1
No known key found for this signature in database
GPG Key ID: BBC71CEE45D86E37

View File

@ -51,7 +51,8 @@ class IconButton(
case _ => // the other modes are triggered on click. case _ => // the other modes are triggered on click.
} }
case ClickEvent(MouseEvent.Button.Left, _) => mode match { case ClickEvent(MouseEvent.Button.Left, _) =>
mode match {
case Mode.Regular => // regular buttons are handled above. case Mode.Regular => // regular buttons are handled above.
case Mode.Switch if model.pressed => case Mode.Switch if model.pressed =>
handleRelease() handleRelease()
@ -62,12 +63,38 @@ class IconButton(
handlePress() handlePress()
clickSoundSource.release.play() clickSoundSource.release.play()
} }
onClicked()
} }
/**
* Called when the state is changed to pressed.
*
* UX note: override this for [[Mode.Switch]] and [[Mode.Radio]] buttons.
*
* @see [[onClicked]] for [[Mode.Regular]] buttons.
*/
def onPressed(): Unit = {} def onPressed(): Unit = {}
/**
* Called when the state is changed to released.
*
* UX note: override this for [[Mode.Switch]] and [[Mode.Radio]] buttons.
*
* @see [[onClicked]] for [[Mode.Regular]] buttons.
*/
def onReleased(): Unit = {} def onReleased(): Unit = {}
/**
* Called when the button is clicked (the mouse button has been released while it's within the button's bounds),
* regardless of the state.
*
* UX note: override this for [[Mode.Regular]] buttons.
*
* @see [[onPressed]] and [[onReleased]] for [[Mode.Switch]] and [[Mode.Radio]] buttons.
*/
def onClicked(): Unit = {}
private def onHoverEnter(): Unit = { private def onHoverEnter(): Unit = {
updateColorAnimationTargets() updateColorAnimationTargets()
@ -178,22 +205,24 @@ object IconButton {
sealed trait Mode sealed trait Mode
object Mode { object Mode {
/**
/** Your regular, run-of-the-mill button you love. * Your regular, run-of-the-mill button you love.
* *
* When the LMB is depressed, [[IconButton.onPressed]] is called. * When the LMB is depressed, [[IconButton.onPressed]] is called.
* After it's released, [[IconButton.onReleased]] is called. * After it's released, [[IconButton.onReleased]] is called.
*/ */
case object Regular extends Mode case object Regular extends Mode
/** A toggleable button, or a switch. /**
* A toggleable button, or a switch.
* *
* Clicking the LMB while the button is pressed releases it, and [[IconButton.onReleased]] is called. * Clicking the LMB while the button is pressed releases it, and [[IconButton.onReleased]] is called.
* Clicking the LMB while the button is released depresses it, and [[IconButton.onPressed]] is called. * Clicking the LMB while the button is released depresses it, and [[IconButton.onPressed]] is called.
*/ */
case object Switch extends Mode case object Switch extends Mode
/** A radio button is like a switch except clicking on it while it's depressed doesn't do anything. /**
* A radio button is like a switch except clicking on it while it's depressed doesn't do anything.
* *
* [[IconButton.onReleased]] is never called (unless you do it yourself). * [[IconButton.onReleased]] is never called (unless you do it yourself).
* *
@ -202,18 +231,21 @@ object IconButton {
case object Radio extends Mode case object Radio extends Mode
} }
/** This is the visible button state. /**
* This is the visible button state.
* *
* When [[IconButton.update]] notices a state change, it runs its animations. * When [[IconButton.update]] notices a state change, it runs its animations.
* *
* Note that callbacks are run after running the setter regardless of whether it does anything. * Note that callbacks are run after running the setter regardless of whether it does anything.
*/ */
trait Model { trait Model {
/**
/** Whether to display the pressed button state. */ * Whether to display the pressed button state.
*/
def pressed: Boolean def pressed: Boolean
/** This setter is used by [[IconButton]] to respond to user interaction. /**
* This setter is used by [[IconButton]] to respond to user interaction.
* *
* You may want to override this method to do nothing * You may want to override this method to do nothing
* if you're proxying another model and updating it in callbacks. * if you're proxying another model and updating it in callbacks.
@ -221,10 +253,14 @@ object IconButton {
def pressed_=(newValue: Boolean): Unit def pressed_=(newValue: Boolean): Unit
} }
/** This is the default model that simply reads from a variable and writes to it. */ /**
* This is the default model that simply reads from a variable and writes to it.
*/
case class DefaultModel(override var pressed: Boolean) extends Model case class DefaultModel(override var pressed: Boolean) extends Model
/** This is a model that ignores user input (presumably you handle it in callbacks). */ /**
* This is a model that ignores user input (presumably you handle it in callbacks).
*/
class ReadOnlyModel(f: () => Boolean) extends Model { class ReadOnlyModel(f: () => Boolean) extends Model {
override def pressed: Boolean = f() override def pressed: Boolean = f()
@ -232,8 +268,8 @@ object IconButton {
} }
object ReadOnlyModel { object ReadOnlyModel {
/**
/** A utility method to create a new instance of [[ReadOnlyModel]]. * A utility method to create a new instance of [[ReadOnlyModel]].
* *
* The value returned by [[ReadOnlyModel.pressed]] is obtained * The value returned by [[ReadOnlyModel.pressed]] is obtained
* by evaluating the provided expression '''every time'''. * by evaluating the provided expression '''every time'''.