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 ClickEvent(MouseEvent.Button.Left, _) => mode match {
case ClickEvent(MouseEvent.Button.Left, _) =>
mode match {
case Mode.Regular => // regular buttons are handled above.
case Mode.Switch if model.pressed =>
handleRelease()
@ -62,12 +63,38 @@ class IconButton(
handlePress()
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 = {}
/**
* 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 = {}
/**
* 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 = {
updateColorAnimationTargets()
@ -178,22 +205,24 @@ object IconButton {
sealed trait 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.
* After it's released, [[IconButton.onReleased]] is called.
*/
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 released depresses it, and [[IconButton.onPressed]] is called.
*/
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).
*
@ -202,18 +231,21 @@ object IconButton {
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.
*
* Note that callbacks are run after running the setter regardless of whether it does anything.
*/
trait Model {
/** Whether to display the pressed button state. */
/**
* Whether to display the pressed button state.
*/
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
* if you're proxying another model and updating it in callbacks.
@ -221,10 +253,14 @@ object IconButton {
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
/** 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 {
override def pressed: Boolean = f()
@ -232,8 +268,8 @@ object IconButton {
}
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
* by evaluating the provided expression '''every time'''.