-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi Sandro,

I finally got my Scala wrapper in a not-too-embarrassing state.  You'll
find it attached to this message.

I must stress that I'm not a Scala or Pivot expert, just an average dev
with a decent-sized hobby project that uses Pivot, a bias against XML,
and a love of static typing.  The Scala abstractions could undoubtedly
be better, and the lib encodes many simplifying assumptions that are ok
for my app, will not be for others.

Still, I hope it's useful to someone.  The ScalaPivot object is
executable, and the Main class shows how things work:

> val window = new Window
> 
> import Implicits._
> 
> val text = label("Here's a label!") 
> 
> text onMouseOver {
>     println("You moused over the label")
> } 
> 
> text onMouseOut {
>     println("You moused out of the label")
> }
> 
> val pane = horizontal(
>     text,
>     button("Here's a button") {
>         println("You pushed the button!")
>     });
> 
> val list = listView("A value", "Another value", "Yet another value") { 
> (index: Int, value: String) =>
>     println("You selected '" + value + "' (position " + index + ")")
> }
> 
> val input = textInput { self: TextInput =>
>     println("So far, you typed '" + self.getText + "'")
> }
> 
> window.setContent(vertical(pane, horizontal(list), horizontal(input)))
> 
> window.open(display)

This grew out of my need to solve certain small problems while porting
my hobby app from Java to Scala class-by-class.  It wraps the tiny slice
of Pivot that the UI part of my app uses most frequently.  A more
general, declarative DSL, perhaps similar to Scala's collection
"literal" syntax is possible with a little effort.


On 12/21/2010 04:46 AM, Sandro Martini wrote:
> 
> Hi Clint,
> I think your code could be really useful even to others (and to me, I like
> very much Scala :-) but too little time to make something real at the
> moment). If you want to post it here, probably it's the best place until
> we'll enable a pivot-contrib project or something similar.
> 
> Or if you are interested, for this or for other things (maybe later), we
> have some project on GoogleCode, so we can enable you to commit there, for
> example pivot-scala, pivot-stuff, etc ...
> 
> Thank you very much,
> Sandro
> 
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)

iEYEARECAAYFAk0kDYoACgkQ0GFaTS4nYxtZwwCcDQHFy09mk22qrsrlZxiPHLcc
aX8AoKEvoSBcZwjEt4WP1gLNt9/eJc5y
=DFZM
-----END PGP SIGNATURE-----
package org.myproject.pivot

import org.apache.pivot.wtk.ComponentMouseListener
import org.apache.pivot.wtk.ListView.SelectMode
import org.apache.pivot.wtk.Orientation
import org.apache.pivot.wtk.Orientation._
import org.apache.pivot.wtk.Label
import org.apache.pivot.wtk.Window
import org.apache.pivot.wtk.Span
import org.apache.pivot.wtk.ListViewSelectionListener
import org.apache.pivot.wtk.ListView
import org.apache.pivot.wtk.TextInputCharacterListener
import org.apache.pivot.wtk.TextInput
import org.apache.pivot.wtk.Container
import org.apache.pivot.wtk.DesktopApplicationContext
import org.apache.pivot.wtk.Display
import org.apache.pivot.wtk.Application
import org.apache.pivot.wtk.Button
import org.apache.pivot.wtk.PushButton
import org.apache.pivot.wtk.BoxPane
import org.apache.pivot.wtk.ComponentMouseButtonListener
import org.apache.pivot.wtk.Component
import org.apache.pivot.wtk.Mouse
import org.apache.pivot.collections.{ Sequence => PSeq }

/**
 * 
 * @author Clint Gilbert
 * 
 * Dec 10, 2010
 *
 * This is in the public domain.  There's no warranty.  I hope someone finds this useful. 
 * If you do use this code, I ask that you please keep my name somewhere in this header.
 */
object ScalaPivot {

    def main(args: Array[String]) = DesktopApplicationContext.main(classOf[Main], args)
    
    final class Main extends ApplicationAdapter {
        override def startup(display: Display, properties: org.apache.pivot.collections.Map[String, String]): Unit = {
            val window = new Window

            import Implicits._

            val text = label("Here's a label!") 
            
            text onMouseOver {
                println("You moused over the label")
            } 
            
            text onMouseOut {
                println("You moused out of the label")
            }
            
            val pane = horizontal(
                text,
                button("Here's a button") {
                    println("You pushed the button!")
                });

            val list = listView("A value", "Another value", "Yet another value") { (index: Int, value: String) =>
                println("You selected '" + value + "' (position " + index + ")")
            }

            val input = textInput { self: TextInput =>
                println("So far, you typed '" + self.getText + "'")
            }

            window.setContent(vertical(pane, horizontal(list), horizontal(input)))

            window.open(display)
        }
    }

    //For convenience
    trait ApplicationAdapter extends Application {
        override def startup(display: Display, properties: org.apache.pivot.collections.Map[String, String]) { }
    
        override def shutdown(optional: Boolean) = false

        override def suspend { } 

        override def resume { }
    }
    
    object Implicits {
        implicit def component2HasMouseHelpers[C <: Component](component: C): HasMouseHelpers[C] = new HasMouseHelpers(component)

        implicit def container2HasContainerHelpers[C <: Container](container: C): HasContainerHelpers[C] = new HasContainerHelpers(container)

        implicit def textInput2HasTextInputHelpers[T <: TextInput](textInput: T): HasTextInputHelpers[T] = new HasTextInputHelpers(textInput)

        implicit def listView2HasListViewHelpers[L <: ListView](listView: L): HasListViewHelpers[L] = new HasListViewHelpers(listView)

        implicit def traversable2PivotList[T](seq: Traversable[T]): org.apache.pivot.collections.List[T] = {
            val result: org.apache.pivot.collections.List[T] = new org.apache.pivot.collections.ArrayList[T]

            seq.foreach(result.add)

            result
        }
    }

    final class HasMouseHelpers[C <: Component](component: C) {
        def onClick(action: (Mouse.Button, Int, Int, Int) => Boolean): C = {
            component.getComponentMouseButtonListeners.add(new ComponentMouseButtonListener.Adapter {
                override def mouseClick(component: Component, button: Mouse.Button, x: Int, y: Int, count: Int) = action(button, x, y, count)
            })

            component
        }

        def onClick(action: => Any): C = {
            component.getComponentMouseButtonListeners.add(new ComponentMouseButtonListener.Adapter {
                override def mouseClick(component: Component, button: Mouse.Button, x: Int, y: Int, count: Int) = { action; true }
            })

            component
        }

        def onDoubleClick(action: (Mouse.Button, Int, Int) => Boolean): C = {
            component.getComponentMouseButtonListeners.add(new ComponentMouseButtonListener.Adapter {
                override def mouseClick(component: Component, button: Mouse.Button, x: Int, y: Int, count: Int) = {
                    if (count == 2) action(button, x, y) else false
                }
            })

            component
        }

        def onDoubleClick(action: => Any): C = {
            component.getComponentMouseButtonListeners.add(new ComponentMouseButtonListener.Adapter {
                override def mouseClick(component: Component, button: Mouse.Button, x: Int, y: Int, count: Int) = {
                    if (count == 2) { action; true } else false
                }
            })

            component
        }

        def onMouseDown(action: (Mouse.Button, Int, Int) => Boolean): C = {
            component.getComponentMouseButtonListeners.add(new ComponentMouseButtonListener.Adapter {
                override def mouseDown(component: Component, button: Mouse.Button, x: Int, y: Int) = action(button, x, y)
            })

            component
        }

        def onMouseDown(action: => Any): C = {
            component.getComponentMouseButtonListeners.add(new ComponentMouseButtonListener.Adapter {
                override def mouseDown(component: Component, button: Mouse.Button, x: Int, y: Int) = { action; true }
            })

            component
        }

        def onMouseUp(action: (Mouse.Button, Int, Int) => Boolean): C = {
            component.getComponentMouseButtonListeners.add(new ComponentMouseButtonListener.Adapter {
                override def mouseUp(component: Component, button: Mouse.Button, x: Int, y: Int) = action(button, x, y)
            })

            component
        }

        def onMouseUp(action: => Any): C = {
            component.getComponentMouseButtonListeners.add(new ComponentMouseButtonListener.Adapter {
                override def mouseUp(component: Component, button: Mouse.Button, x: Int, y: Int) = { action; true }
            })

            component
        }
        
        def onMouseOver(action: => Any): C = {
            component.getComponentMouseListeners.add(new ComponentMouseListener.Adapter {
                override def mouseOver(component: Component): Unit = action
            })
            
            component
        }
        
        def onMouseOut(action: => Any): C = {
            component.getComponentMouseListeners.add(new ComponentMouseListener.Adapter {
                override def mouseOut(component: Component): Unit = action
            })
            
            component
        }
    }

    final class HasContainerHelpers[C <: Container](container: C) {

        def addAll[T <: Component](toBeAdded: Traversable[T]): C = addAll(container, toBeAdded)

        private def addAll[T <: Component](container: C, toBeAdded: Traversable[T]): C = {
            toBeAdded.foreach(container.add)

            container
        }

        private def add[T <: Component](container: C, toBeAdded: T): C = {
            container.add(toBeAdded)

            container
        }

        def ++=[T <: Component](toBeAdded: Traversable[T]): C = addAll(toBeAdded)

        def ++=[T <: Component](toBeAdded: T*): C = addAll(toBeAdded)

        def +=[T <: Component](toBeAdded: T): C = add(container, toBeAdded)
    }

    final class HasTextInputHelpers[T <: TextInput](textInput: T) {
        def onTyping(action: => Any): T = {
            textInput.getTextInputCharacterListeners.add(new TextInputCharacterListener.Adapter {
                override def charactersInserted(textInput: TextInput, index: Int, count: Int): Unit = action
                override def charactersRemoved(textInput: TextInput, index: Int, count: Int): Unit = action
            })

            textInput
        }

        def onTyping(action: TextInput => Any): T = {
            textInput.getTextInputCharacterListeners.add(new TextInputCharacterListener.Adapter {
                override def charactersInserted(textInput: TextInput, index: Int, count: Int): Unit = action(textInput)
                override def charactersRemoved(textInput: TextInput, index: Int, count: Int): Unit = action(textInput)
            })

            textInput
        }
    }

    final class HasListViewHelpers[L <: ListView](listView: L) {
        def onSelect(action: Int => Any): L = {
            listView.getListViewSelectionListeners.add(new ListViewSelectionListener.Adapter {
                override def selectedRangesChanged(listView: ListView, previousSelectedRanges: PSeq[Span]): Unit = action(listView.getSelectedIndex)
            })
            
            listView
        }

        /**
         * Not type-safe, unfortunately, as a Pivot ListView's model is a list of Objects
         */
        def onSelect[T](action: (Int, T) => Any): L = {
            listView.getListViewSelectionListeners.add(new ListViewSelectionListener.Adapter {
                override def selectedRangesChanged(listView: ListView, previousSelectedRanges: PSeq[Span]): Unit = action(listView.getSelectedIndex, listView.getSelectedItem.asInstanceOf[T])
            })
            
            listView
        }
    }

    import Implicits._

    def horizontal(components: Component*) = makePane(HORIZONTAL) ++= components

    def vertical(components: Component*) = makePane(VERTICAL) ++= components

    private def makePane(orientation: Orientation) = new BoxPane(orientation)

    def label(text: String): Label = new Label(text)

    def button(text: String)(action: => Any): Button = (new PushButton(text)) onClick action

    def textInput(action: => Any): TextInput = (new TextInput) onTyping action
    def textInput(action: TextInput => Any): TextInput = (new TextInput) onTyping action

    def makeListView[T](data: Seq[T]): ListView = {
        val result = new ListView(data)

        result.setSelectMode(SelectMode.SINGLE)

        result
    }

    def listView[T](data: T*)(action: (Int, T) => Any): ListView = makeListView(data) onSelect action
}

Reply via email to