All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.sciss.mellite.impl.objview.DoubleObjView.scala Maven / Gradle / Ivy

/*
 *  DoubleObjView.scala
 *  (Mellite)
 *
 *  Copyright (c) 2012-2023 Hanns Holger Rutz. All rights reserved.
 *
 *  This software is published under the GNU Affero General Public License v3+
 *
 *
 *  For further information, please contact Hanns Holger Rutz at
 *  [email protected]
 */

package de.sciss.mellite.impl.objview

import de.sciss.desktop
import de.sciss.kollflitz.Vec
import de.sciss.lucre.expr.graph.Ex
import de.sciss.lucre.synth.Txn
import de.sciss.lucre.{DoubleObj, Expr, Source, Txn => LTxn}
import de.sciss.mellite.impl.ObjGraphemeViewImpl
import de.sciss.mellite.impl.objview.ObjViewImpl.raphaelIcon
import de.sciss.mellite.{GraphemeRendering, GraphemeView, Insets, ObjGraphemeView, ObjListView, ObjView, Shapes}
import de.sciss.proc.Grapheme.Entry
import de.sciss.proc.{Code, Confluent, Universe}
import de.sciss.swingplus.Spinner
import org.rogach.scallop

import javax.swing.{Icon, SpinnerNumberModel}
import scala.swing.{Component, Graphics2D, Label}
import scala.util.Try

object DoubleObjView extends ObjListView.Factory with ObjGraphemeView.Factory with ProgramSupport {
  type E[T <: LTxn[T]]          = DoubleObj[T]
  val icon          : Icon      = raphaelIcon(Shapes.RealNumber)
  val prefix        : String    = "Double"
  def humanName     : String    = prefix
  def category      : String    = ObjView.categPrimitives
  type Elem                     = Double

  def tpe     : Expr.Type[Elem, E]          = DoubleObj
  val codeType: Code.TypeT[Unit, Ex[Elem]]  = Code.Program.Double

  override protected def scallopValueConverter: scallop.ValueConverter[Elem] = scallop.doubleConverter

  def mkListView[T <: Txn[T]](obj: E[T])(implicit tx: T): DoubleObjView[T] with ObjListView[T] = {
    val ex          = obj
    val value       = ex.value
    val isEditable  = Expr.isVar(ex)
    val isProgram   = Expr.isProgram(ex)
    val isViewable = isProgram || tx.isInstanceOf[Confluent.Txn]
    new ListImpl[T](tx.newHandle(obj), value, isListCellEditable = isEditable, isProgram = isProgram,
      isViewable = isViewable).init(obj)
  }

  override def initMakeDialog[T <: Txn[T]](window: Option[desktop.Window])
                                          (implicit universe: Universe[T]): MakeResult[T] = {
    val model       = new SpinnerNumberModel(0.0, Double.NegativeInfinity, Double.PositiveInfinity, 1.0)
    val ggValue     = new Spinner(model)
    val codeValue0  = "0.0"
    showMakeDialog(ggValue = ggValue, codeValue0 = codeValue0, prefix = prefix,
      window = window)(model.getNumber.doubleValue())
  }

  def mkGraphemeView[T <: Txn[T]](entry: Entry[T], obj: E[T], mode: GraphemeView.Mode)
                                 (implicit tx: T): ObjGraphemeView[T] = {
    val isViewable  = tx.isInstanceOf[Confluent.Txn]
    // assert (entry.value == value)
    new GraphemeImpl[T](tx.newHandle(entry), tx.newHandle(obj), value = obj.value, isViewable = isViewable)
      .init(obj, entry)
  }

  // ---- ListObjView ----

  private final class ListImpl[T <: Txn[T]](val objH: Source[T, E[T]], var value: Double,
                                            override val isListCellEditable: Boolean, val isProgram: Boolean,
                                            val isViewable: Boolean)
    extends DoubleObjView[T] with ListBase[T]
      with ObjListViewImpl.SimpleExpr[T, Elem, E] {

    override def configureListCellRenderer(label: Label): Component = {
      val valueS = value.toFloat.toString // avoid excessive number of digits!
      label.text = if (isProgram) s"= $valueS" else valueS
      label
    }

    def convertEditValue(v: Any): Option[Double] = v match {
      case num: Elem    => Some(num)
      case s  : String  => Try(s.toDouble).toOption
      case _            => None
    }
  }

  // ---- GraphemeObjView ----

  def graphemePaintFront[T <: Txn[T]](view: ObjGraphemeView[T], value: Double, g: Graphics2D,
                                      gv: GraphemeView[T], r: GraphemeRendering): Unit = {
    import ObjGraphemeView.{HandleDiameter, HandleRadius}
    val c         = gv.canvas
    val selected  = gv.selectionModel.contains(view)
    val time0     = view.timeValue
    val time1     = if (selected) time0 + r.ttMoveState.deltaTime    else time0
    val value1    = if (selected) value + r.ttMoveState.deltaModelY  else value
    val x         = c.frameToScreen   (time1  )
    val y         = c.modelPosToScreen(value1 )
    val p         = r.ellipse1
    p.setFrame(x - 2, y - 2, 4, 4)
    g.setPaint(if (selected) r.pntRegionBackgroundSelected else r.pntRegionBackground)
    g.fill(p)
    p.setFrame(x - HandleRadius, y - HandleRadius, HandleDiameter, HandleDiameter)
    g.setPaint(if (selected) r.pntRegionOutlineSelected else r.pntRegionOutline)
    g.draw(p)
  }

  private final class GraphemeImpl[T <: Txn[T]](val entryH: Source[T, Entry[T]],
                                                val objH: Source[T, E[T]],
                                                var value: Elem,
                                                val isViewable: Boolean)
    extends Base[T]
    with ObjGraphemeViewImpl.SimpleExpr[T, Elem, E]
    with ObjGraphemeView.HasStartLevels[T] {

    def insets: Insets = ObjGraphemeView.DefaultInsets

    def startLevels: Vec[Double] = value +: Vector.empty

    override def paintFront(g: Graphics2D, gv: GraphemeView[T], r: GraphemeRendering): Unit =
      graphemePaintFront(this, value, g, gv, r)
  }
}
trait DoubleObjView[T <: LTxn[T]] extends ObjView[T] {
  type Repr = DoubleObj[T]
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy