Skip to content
Open
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
4 changes: 2 additions & 2 deletions README
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
The scala.swing package

This is a UI library that will wrap most of Java Swing for Scala in a straightforward manner.
This is a UI library that will wrap most of Java Swing for Scala in a straightforward manner.
The widget class hierarchy loosely resembles that of Java Swing.

The library comprises three main packages:

scala.swing
All widget classes and traits.

scala.swing.event
The event hierarchy.

Expand Down
32 changes: 16 additions & 16 deletions doc/README
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
scala.swing BETA

This is a UI library that will wrap most of Java Swing for Scala in a straightforward manner.
This is a UI library that will wrap most of Java Swing for Scala in a straightforward manner.
The widget class hierarchy loosely resembles that of Java Swing. The main differences are:

In Java Swing all components are containers per default. This doesn't make much sense for
a number of components, like TextField, CheckBox, RadioButton, and so on. Our guess is that
this architecture was chosen because Java lacks multiple inheritance.
In Java Swing all components are containers per default. This doesn't make much sense for
a number of components, like TextField, CheckBox, RadioButton, and so on. Our guess is that
this architecture was chosen because Java lacks multiple inheritance.
In scala.swing, components that can have child components extend the Container trait.
Layout managers and panels are coupled. There is no way to exchange the layout manager
of a panel. As a result, the layout constraints for widgets can be typed.
(Note that you gain more type-safety and don't loose much flexibility here. Besides
being not a common operation, exchanging the layout manager of a panel in Java
Swing almost always leads to exchanging the layout constraints for every of the panel's
child component. In the end, it is not more work to move all children to a newly created

Layout managers and panels are coupled. There is no way to exchange the layout manager
of a panel. As a result, the layout constraints for widgets can be typed.
(Note that you gain more type-safety and don't loose much flexibility here. Besides
being not a common operation, exchanging the layout manager of a panel in Java
Swing almost always leads to exchanging the layout constraints for every of the panel's
child component. In the end, it is not more work to move all children to a newly created
panel.)

The event system. TODO


The library comprises three main packages:

scala.swing
All widget classes and traits.

scala.swing.event
The event hierarchy.

scala.swing.test
A set of demos.


Notes:

Visual appearance of combo boxes using the GTK LaF is broken on JDKs < 1.7b30.
Visual appearance of combo boxes using the GTK LaF is broken on JDKs < 1.7b30.
This is a Java Swing problem.

To download the latest version, go to http://lamp.epfl.ch/~imaier or use sbaz.
32 changes: 16 additions & 16 deletions scala/swing/AbstractButton.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ import event._
import javax.swing.{AbstractButton => JAbstractButton, Icon}

/**
* Base class of all button-like widgets, such as push buttons,
* Base class of all button-like widgets, such as push buttons,
* check boxes, and radio buttons.
*
*
* @see javax.swing.AbstractButton
*/
abstract class AbstractButton extends Component with Action.Trigger.Wrapper with Publisher {
override lazy val peer: JAbstractButton = new JAbstractButton with SuperMixin {}

def text: String = peer.getText
def text_=(s: String) = peer.setText(s)

def icon: Icon = peer.getIcon
def icon_=(i: Icon) = peer.setIcon(i)
def pressedIcon: Icon = peer.getPressedIcon
Expand All @@ -39,49 +39,49 @@ abstract class AbstractButton extends Component with Action.Trigger.Wrapper with
def rolloverIcon_=(b: Icon) = peer.setRolloverIcon(b)
def rolloverSelectedIcon: Icon = peer.getRolloverSelectedIcon
def rolloverSelectedIcon_=(b: Icon) = peer.setRolloverSelectedIcon(b)

peer.addActionListener(Swing.ActionListener { e =>
publish(ButtonClicked(AbstractButton.this))
})

def selected: Boolean = peer.isSelected
def selected_=(b: Boolean) = peer.setSelected(b)

def contentAreaFilled: Boolean = peer.isContentAreaFilled
def contentAreaFilled_=(b: Boolean) { peer.setContentAreaFilled(b) }

def borderPainted: Boolean = peer.isBorderPainted
def borderPainted_=(b: Boolean) { peer.setBorderPainted(b) }
def focusPainted: Boolean = peer.isFocusPainted
def focusPainted_=(b: Boolean) { peer.setFocusPainted(b) }

def rolloverEnabled: Boolean = peer.isRolloverEnabled
def rolloverEnabled_=(b: Boolean) = peer.setRolloverEnabled(b)

def verticalTextPosition: Alignment.Value = Alignment(peer.getVerticalTextPosition)
def verticalTextPosition_=(a: Alignment.Value) { peer.setVerticalTextPosition(a.id) }
def verticalAlignment: Alignment.Value = Alignment(peer.getVerticalAlignment)
def verticalAlignment_=(a: Alignment.Value) { peer.setVerticalAlignment(a.id) }

def horizontalTextPosition: Alignment.Value = Alignment(peer.getHorizontalTextPosition)
def horizontalTextPosition_=(a: Alignment.Value) { peer.setHorizontalTextPosition(a.id) }
def horizontalAlignment: Alignment.Value = Alignment(peer.getHorizontalAlignment)
def horizontalAlignment_=(a: Alignment.Value) { peer.setHorizontalAlignment(a.id) }

def iconTextGap: Int = peer.getIconTextGap
def iconTextGap_=(x: Int) { peer.setIconTextGap(x) }

def mnemonic: Key.Value = Key(peer.getMnemonic)
def mnemonic_=(k: Key.Value) { peer.setMnemonic(k.id) }
def mnemonic_=(k: Key.Value) { peer.setMnemonic(k.id) }
def displayedMnemonicIndex: Int = peer.getDisplayedMnemonicIndex
def displayedMnemonicIndex_=(n: Int) { peer.setDisplayedMnemonicIndex(n) }

def multiClickThreshold: Long = peer.getMultiClickThreshhold
def multiClickThreshold_=(n: Long) { peer.setMultiClickThreshhold(n) }

def doClick() { peer.doClick() }
def doClick() { peer.doClick() }
def doClick(times: Int) { peer.doClick(times) }

def margin: Insets = peer.getMargin
def margin_=(i: Insets) { peer.setMargin(i) }
}
92 changes: 46 additions & 46 deletions scala/swing/Action.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,74 +16,74 @@ import java.awt.event.ActionListener
object Action {
/**
* Special action that has an empty title and all default properties and does nothing.
* Use this as a "null action", i.e., to tell components that they do not have any
* associated action. A component may then obtain its properties from its direct members
* Use this as a "null action", i.e., to tell components that they do not have any
* associated action. A component may then obtain its properties from its direct members
* instead of from its action.
* In Java Swing, one would use `null` instead of a designated action.
*/
case object NoAction extends Action("") { def apply() {} }

object Trigger {
trait Wrapper extends Action.Trigger {
def peer: javax.swing.JComponent {
def addActionListener(a: ActionListener)
trait Wrapper extends Action.Trigger {
def peer: javax.swing.JComponent {
def addActionListener(a: ActionListener)
def removeActionListener(a: ActionListener)
def setAction(a: javax.swing.Action)
def getAction(): javax.swing.Action
}

// TODO: we need an action cache
private var _action: Action = Action.NoAction
def action: Action = _action
def action_=(a: Action) { _action = a; peer.setAction(a.peer) }

//1.6: def hideActionText: Boolean = peer.getHideActionText
//def hideActionText_=(b: Boolean) = peer.setHideActionText(b)
}
}

/**
* Something that triggers an action.
*/
trait Trigger {
def action: Action
def action_=(a: Action)

//1.6: def hideActionText: Boolean
//def hideActionText_=(b: Boolean)
}

/**
* Convenience method to create an action with a given title and body to run.
*/
def apply(title: String)(body: =>Unit) = new Action(title) {
def apply(title: String)(body: =>Unit) = new Action(title) {
def apply() { body }
}
}

/**
* An abstract action to be performed in reaction to user input.
*
* Not every action component will honor every property of its action.
* An action itself can generally be configured so that certain properties
* should be ignored and instead taken from the component directly. In the
*
* Not every action component will honor every property of its action.
* An action itself can generally be configured so that certain properties
* should be ignored and instead taken from the component directly. In the
* end, it is up to a component which property it uses in which way.
*
*
* @see javax.swing.Action
*/
abstract class Action(title0: String) {
import Swing._

lazy val peer: javax.swing.Action = new javax.swing.AbstractAction(title0) {
def actionPerformed(a: java.awt.event.ActionEvent) = apply()
}

/**
* Title is not optional.
*/
def title: String = ifNull(peer.getValue(javax.swing.Action.NAME),"")
def title_=(t: String) { peer.putValue(javax.swing.Action.NAME, t) }

/**
* None if large icon and small icon are not equal.
*/
Expand All @@ -93,65 +93,65 @@ abstract class Action(title0: String) {
// def largeIcon_=(i: Icon) { peer.putValue(javax.swing.Action.LARGE_ICON_KEY, toNullIcon(i)) }
def smallIcon: Icon = toNoIcon(peer.getValue(javax.swing.Action.SMALL_ICON).asInstanceOf[Icon])
def smallIcon_=(i: Icon) { peer.putValue(javax.swing.Action.SMALL_ICON, toNullIcon(i)) }

/**
* For all components.
*/
def toolTip: String =
ifNull(peer.getValue(javax.swing.Action.SHORT_DESCRIPTION), "")
def toolTip_=(t: String) {
peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, t)
def toolTip: String =
ifNull(peer.getValue(javax.swing.Action.SHORT_DESCRIPTION), "")
def toolTip_=(t: String) {
peer.putValue(javax.swing.Action.SHORT_DESCRIPTION, t)
}
/**
* Can be used for status bars, for example.
*/
def longDescription: String =
ifNull(peer.getValue(javax.swing.Action.LONG_DESCRIPTION), "")
def longDescription_=(t: String) {
peer.putValue(javax.swing.Action.LONG_DESCRIPTION, t)
def longDescription: String =
ifNull(peer.getValue(javax.swing.Action.LONG_DESCRIPTION), "")
def longDescription_=(t: String) {
peer.putValue(javax.swing.Action.LONG_DESCRIPTION, t)
}

/**
* Default: java.awt.event.KeyEvent.VK_UNDEFINED, i.e., no mnemonic key.
* For all buttons and thus menu items.
*/
def mnemonic: Int = ifNull(peer.getValue(javax.swing.Action.MNEMONIC_KEY),
def mnemonic: Int = ifNull(peer.getValue(javax.swing.Action.MNEMONIC_KEY),
java.awt.event.KeyEvent.VK_UNDEFINED)
def mnemonic_=(m: Int) { peer.putValue(javax.swing.Action.MNEMONIC_KEY, m) }

/*/**
* Indicates which character of the title should be underlined to indicate the mnemonic key.
* Ignored if out of bounds of the title string. Default: -1, i.e., ignored.
* Ignored if out of bounds of the title string. Default: -1, i.e., ignored.
* For all buttons and thus menu items.
*/
1.6: def mnemonicIndex: Int =
1.6: def mnemonicIndex: Int =
ifNull(peer.getValue(javax.swing.Action.DISPLAYED_MNEMONIC_INDEX_KEY), -1)
def mnemonicIndex_=(n: Int) { peer.putValue(javax.swing.Action.DISPLAYED_MNEMONIC_INDEX_KEY, n) }
*/

/**
* For menus.
*/
def accelerator: Option[KeyStroke] =
def accelerator: Option[KeyStroke] =
toOption(peer.getValue(javax.swing.Action.ACCELERATOR_KEY))
def accelerator_=(k: Option[KeyStroke]) {
def accelerator_=(k: Option[KeyStroke]) {
peer.putValue(javax.swing.Action.ACCELERATOR_KEY, k orNull)
}
}

/**
* For all components.
*/
def enabled: Boolean = peer.isEnabled
def enabled: Boolean = peer.isEnabled
def enabled_=(b: Boolean) { peer.setEnabled(b) }

/*/**
* Only honored if not <code>None</code>. For various buttons.
*/
1.6: def selected: Option[Boolean] = Option(peer.getValue(javax.swing.Action.SELECTED_KEY))
def selected_=(b: Option[Boolean]) {
peer.putValue(javax.swing.Action.SELECTED_KEY,
if (b == None) null else new java.lang.Boolean(b.get))
}*/
def selected_=(b: Option[Boolean]) {
peer.putValue(javax.swing.Action.SELECTED_KEY,
if (b == None) null else new java.lang.Boolean(b.get))
}*/

def apply()
}
4 changes: 2 additions & 2 deletions scala/swing/Adjustable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ trait Adjustable extends Oriented {
def minimum_=(m: Int)
def maximum: Int
def maximum_=(m: Int)

// Needs implementation of AdjustmentEvent
//
// val adjustments: Publisher = new Publisher {
// peer.addAdjustmentListener(new AdjustmentListener {
// def adjustmentValueChanged(e: java.awt.event.AdjustmentEvent) {
// def adjustmentValueChanged(e: java.awt.event.AdjustmentEvent) {
// publish(new AdjustmentEvent(e))
// }
// })
Expand Down
4 changes: 2 additions & 2 deletions scala/swing/Alignment.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import javax.swing.SwingConstants._
/**
* Horizontal and vertical alignments. We sacrifice a bit of type-safety
* for simplicity here.
*
*
* @see javax.swing.SwingConstants
*/
object Alignment extends Enumeration {
Expand All @@ -25,7 +25,7 @@ object Alignment extends Enumeration {
val Top = Value(TOP)
val Bottom = Value(BOTTOM)
//1.6: val Baseline = Value(BASELINE)

val Leading = Value(LEADING)
val Trailing = Value(TRAILING)
}
Expand Down
6 changes: 3 additions & 3 deletions scala/swing/Applet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ import javax.swing.JApplet
* <p>
* <b>Note</b>: <code>Applet</code> extends <code>javax.swing.JApplet</code>
* to satisfy Java's applet loading mechanism. The usual component wrapping
* scheme doesn't work here.
* scheme doesn't work here.
* </p>
*
* @see javax.swing.JApplet
*/
abstract class Applet extends JApplet { outer =>
val ui: UI

override def init() { ui.init() }
override def start() { ui.start() }
override def stop() { ui.stop() }

abstract class UI extends RootPanel {
def peer = outer
override def contents_=(c: Component) {
Expand Down
Loading