diff options
Diffstat (limited to 'src/swing')
55 files changed, 994 insertions, 123 deletions
diff --git a/src/swing/scala/swing/Action.scala b/src/swing/scala/swing/Action.scala new file mode 100644 index 0000000000..627d9468b9 --- /dev/null +++ b/src/swing/scala/swing/Action.scala @@ -0,0 +1,110 @@ +package scala.swing + +import javax.swing.{KeyStroke, Icon} + +object Action { + case object NoAction extends Action("") { def apply() {} } + + /** + * Anything that triggers an action. + */ + trait Trigger { + def action: Action + def action_=(a: Action) + + def hideActionText: Boolean + def hideActionText_=(b: Boolean) + } +} + +/** + * 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. + */ + def icon: Option[Icon] = if(largeIcon == smallIcon) largeIcon else None + def icon_=(i: Option[Icon]) { largeIcon = i; smallIcon = i } + def largeIcon: Option[Icon] = toOption(peer.getValue(javax.swing.Action.LARGE_ICON_KEY)) + def largeIcon_=(i: Option[Icon]) { peer.putValue(javax.swing.Action.LARGE_ICON_KEY, toNull(i)) } + def smallIcon: Option[Icon] = toOption(peer.getValue(javax.swing.Action.SMALL_ICON)) + def smallIcon_=(i: Option[Icon]) { peer.putValue(javax.swing.Action.SMALL_ICON, toNull(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) + } + /** + * 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) + } + + /** + * 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), + 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. + * For all buttons and thus menu items. + */ + 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] = + toOption(peer.getValue(javax.swing.Action.ACCELERATOR_KEY)) + def accelerator_=(k: Option[KeyStroke]) { + peer.putValue(javax.swing.Action.ACCELERATOR_KEY, toNull(k)) + } + + /** + * For all components. + */ + def enabled: Boolean = peer.isEnabled + def enabled_=(b: Boolean) { peer.setEnabled(b) } + + /** + * Only honored if not <code>None</code>. For various buttons. + */ + def selected: Option[Boolean] = toOption(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 apply() +} diff --git a/src/swing/scala/swing/BoxPanel.scala b/src/swing/scala/swing/BoxPanel.scala index d8af118ef9..6520224f04 100644 --- a/src/swing/scala/swing/BoxPanel.scala +++ b/src/swing/scala/swing/BoxPanel.scala @@ -1,11 +1,10 @@ package scala.swing -class BoxPanel(orientation: Orientation)(content0: Component*) extends IndexedPanel { +class BoxPanel(orientation: Orientation) extends Panel with IndexedContainer { override lazy val peer = { val p = new javax.swing.JPanel val l = new javax.swing.BoxLayout(p, orientation.peer) p.setLayout(l) p } - content ++ content0 } diff --git a/src/swing/scala/swing/BufferAdapter.scala b/src/swing/scala/swing/BufferAdapter.scala new file mode 100644 index 0000000000..4e0c4b9d09 --- /dev/null +++ b/src/swing/scala/swing/BufferAdapter.scala @@ -0,0 +1,30 @@ +package scala.swing + +import scala.collection.mutable.Buffer + +/** + * Default partial implementation for buffer adapters. + */ +protected[swing] abstract class BufferAdapter[A] extends Buffer[A] { outer => + def clear { for (i <- 0 to length) remove(0) } + def update(n: Int, a: A) { + remove(0) + insertAt(n, a) + } + def insertAll(n: Int, iter: Iterable[A]) { + var i = n + for(el <- iter) { + insertAt(i, el) + i += 1 + } + } + protected def insertAt(n: Int, a: A) + + def readOnly : RandomAccessSeq[A] = new RandomAccessSeq[A] { + def length = outer.length + def apply(idx : Int) = outer.apply(idx) + override def stringPrefix = outer.stringPrefix + "RO" + } + def +:(a: A): this.type = { insertAt(0, a); this } + def elements = Iterator.range(0,length).map(apply(_)) +} diff --git a/src/swing/scala/swing/ButtonMutex.scala b/src/swing/scala/swing/ButtonMutex.scala new file mode 100644 index 0000000000..4edae73b9d --- /dev/null +++ b/src/swing/scala/swing/ButtonMutex.scala @@ -0,0 +1,27 @@ +package scala.swing + +import javax.swing.{AbstractButton => JAbstractButton,Icon} +import event._ +import scala.collection._ + + +class ButtonMutex(initialButtons: Button*) { + val peer: javax.swing.ButtonGroup = new javax.swing.ButtonGroup + + val buttons: mutable.Set[Button] = new mutable.Set[Button] { + def -=(b: Button) { peer.remove(b.peer) } + def +=(b: Button) { peer.add(b.peer) } + def contains(b: Button) = elements.contains(b) + def size = peer.getButtonCount + def elements: Iterator[Button] = new Iterator[Button] { + val enum = peer.getElements + def next = Component.wrapperFor[Button](enum.nextElement) + def hasNext = enum.hasMoreElements + } + } + buttons ++= initialButtons + + def deselectAll() { peer.clearSelection } + def selected: Option[Selectable] = buttons.find(_.selected) + def select(b: Selectable) { b.selected = true } +} diff --git a/src/swing/scala/swing/CheckBox.scala b/src/swing/scala/swing/CheckBox.scala new file mode 100644 index 0000000000..7851c8c75d --- /dev/null +++ b/src/swing/scala/swing/CheckBox.scala @@ -0,0 +1,8 @@ +package scala.swing + +import javax.swing._ + +class CheckBox(override val peer: JCheckBox) extends ToggleButton { + def this(txt: String) = this(new JCheckBox(txt)) + def this() = this(new JCheckBox) +}
\ No newline at end of file diff --git a/src/swing/scala/swing/Component.scala b/src/swing/scala/swing/Component.scala index 2d3a319b0b..bb9c76f1f9 100644 --- a/src/swing/scala/swing/Component.scala +++ b/src/swing/scala/swing/Component.scala @@ -1,6 +1,7 @@ package scala.swing import event._ +import geometry._ import java.awt.Font import java.awt.event._ import javax.swing.JComponent @@ -11,7 +12,6 @@ object Component { def wrapperFor[C<:Component](c: javax.swing.JComponent): C = c.getClientProperty(ClientKey).asInstanceOf[C] } - abstract class Component extends UIElement with Showable.Swing with Publisher { lazy val peer: javax.swing.JComponent = new javax.swing.JComponent {} peer.putClientProperty(Component.ClientKey, this) @@ -26,19 +26,22 @@ abstract class Component extends UIElement with Showable.Swing with Publisher { def xAlignment: Double = peer.getAlignmentX def xAlignment_=(x: Double) = peer.setAlignmentX(x.toFloat) def yAlignment: Double = peer.getAlignmentY - def yAlignment_=(x: Double) = peer.setAlignmentY(x.toFloat) + def yAlignment_=(y: Double) = peer.setAlignmentY(y.toFloat) def foreground: Color = new Color(peer.getForeground) - def foreground_=(x: Color) = peer.setForeground(x) + def foreground_=(c: Color) = peer.setForeground(c) def background: Color = new Color(peer.getBackground) - def background_=(x: Color) = peer.setBackground(x) + def background_=(c: Color) = peer.setBackground(c) def border: Border = peer.getBorder - def border_=(x: Border) { peer.setBorder(x) } + def border_=(b: Border) { peer.setBorder(b) } def font: Font = peer.getFont - def font_=(x: Font) = peer.setFont(x) + def font_=(f: Font) = peer.setFont(f) def opaque: Boolean = peer.isOpaque - def opaque_=(x: Boolean) = peer.setOpaque(x) + def opaque_=(b: Boolean) = peer.setOpaque(b) + + def enabled: Boolean = peer.isEnabled + def enabled_=(b: Boolean) = peer.setEnabled(b) def tooltip: String = peer.getToolTipText def tooltip_=(t: String) = peer.setToolTipText(t) diff --git a/src/swing/scala/swing/ComponentList.scala b/src/swing/scala/swing/ComponentList.scala index 6582b08b5a..31e48e65b1 100644 --- a/src/swing/scala/swing/ComponentList.scala +++ b/src/swing/scala/swing/ComponentList.scala @@ -3,13 +3,13 @@ package scala.swing import javax.swing._ import event._ -class ComponentList(val jlist: JList) extends Container(jlist) with Publisher { +class ComponentList(override val peer: JList) extends Component with Container with Publisher { def this() = this(new JList) def this(elems: Seq[Object]) = this(new JList(elems.toArray)) - def fixedCellWidth = jlist.getFixedCellWidth - def fixedCellWidth_=(x: Int) = jlist.setFixedCellWidth(x) + def fixedCellWidth = peer.getFixedCellWidth + def fixedCellWidth_=(x: Int) = peer.setFixedCellWidth(x) - def fixedCellHeight = jlist.getFixedCellHeight - def fixedCellHeight_=(x: Int) = jlist.setFixedCellHeight(x) + def fixedCellHeight = peer.getFixedCellHeight + def fixedCellHeight_=(x: Int) = peer.setFixedCellHeight(x) } diff --git a/src/swing/scala/swing/Container.scala b/src/swing/scala/swing/Container.scala index 896ecc03d3..674fbee796 100644 --- a/src/swing/scala/swing/Container.scala +++ b/src/swing/scala/swing/Container.scala @@ -3,35 +3,21 @@ package scala.swing import event._ import scala.collection.mutable.Buffer -abstract class Container(override val peer: javax.swing.JComponent) extends Component { - def this() = this(new javax.swing.JComponent {}) - def content: Seq[Component] = new Content +trait Container extends Component { + protected val _contents = new Content + def contents: Seq[Component] = _contents - protected class Content extends Buffer[Component] { + protected class Content extends BufferAdapter[Component] { def wrap(c: java.awt.Component) = Component.wrapperFor(c.asInstanceOf[javax.swing.JComponent]) - def clear = peer.removeAll() + override def clear { peer.removeAll() } def remove(n: Int): Component = { val c = peer.getComponent(n) peer.remove(n) wrap(c) } - def update(n: Int, c: Component) { peer.add(c.peer, n) } - def insertAll(n: Int, iter: Iterable[Component]) { - var i = n - for(el <- iter) { - peer.add(el.peer, i) - i += 1 - } - } - def readOnly : RandomAccessSeq[Component] = new RandomAccessSeq[Component] { - def length = Content.this.length - def apply(idx : Int) = Content.this.apply(idx) - override def stringPrefix = Content.this.stringPrefix + "RO" - } - def +:(c: Component): Buffer[Component] = { update(0, c); this } - def +=(c: Component) { peer.add(c.peer); this } + protected def insertAt(n: Int, c: Component) { peer.add(c.peer, n) } + def +=(c: Component) { peer.add(c.peer) } def length = peer.getComponentCount - def elements = peer.getComponents.projection.map(wrap(_)).elements def apply(n: Int) = wrap(peer.getComponent(n)) } diff --git a/src/swing/scala/swing/FlowPanel.scala b/src/swing/scala/swing/FlowPanel.scala index 6d9a2189b5..8842d2fcf6 100644 --- a/src/swing/scala/swing/FlowPanel.scala +++ b/src/swing/scala/swing/FlowPanel.scala @@ -1,6 +1,24 @@ package scala.swing -class FlowPanel(orientation: Orientation)(content0: Component*) extends IndexedPanel { - override lazy val peer = new javax.swing.JPanel(new java.awt.FlowLayout(orientation.peer)) - content ++ content0 +import java.awt.FlowLayout + +object FlowPanel { + object Alignment extends Enumeration { + val Leading = Value(FlowLayout.LEADING) + val Trailing = Value(FlowLayout.TRAILING) + val Left = Value(FlowLayout.LEFT) + val Right = Value(FlowLayout.RIGHT) + val Center = Value(FlowLayout.CENTER) + } +} + +class FlowPanel(alignment: FlowPanel.Alignment.Value) extends Panel with IndexedContainer { + def this() = this(FlowPanel.Alignment.Center) + override lazy val layoutManager = new java.awt.FlowLayout(alignment.id) + override lazy val peer = new javax.swing.JPanel(layoutManager) + + def vGap: Int = layoutManager.getVgap + def vGap_=(n: Int) { layoutManager.setVgap(n) } + def hGap: Int = layoutManager.getHgap + def hGap_=(n: Int) { layoutManager.setHgap(n) } } diff --git a/src/swing/scala/swing/Frame.scala b/src/swing/scala/swing/Frame.scala index 7a690a78f4..93e805e322 100644 --- a/src/swing/scala/swing/Frame.scala +++ b/src/swing/scala/swing/Frame.scala @@ -11,20 +11,22 @@ class Frame(val peer: JFrame) extends UIElement with RootPanel with Showable.Swi override def content_=(c: Component) { super.content_=(c) - peer.pack() // pack also validates, which is generally required after an add} + peer.pack() // pack also validates, which is generally required after an add } - def defaultButton: Button = Component.wrapperFor(peer.getRootPane.getDefaultButton) - def defaultButton_=(b: Button) { peer.getRootPane.setDefaultButton(b.peer) } + def defaultButton: PushButton = Component.wrapperFor(peer.getRootPane.getDefaultButton) + def defaultButton_=(b: PushButton) { peer.getRootPane.setDefaultButton(b.peer) } def pack(): this.type = { peer.pack(); this } - peer.addWindowListener { - new java.awt.event.WindowListener { - def windowActivated(e: java.awt.event.WindowEvent) = publish(WindowActivated(Frame.this)) - def windowClosed(e: java.awt.event.WindowEvent) = publish(WindowClosed(Frame.this)) - def windowClosing(e: java.awt.event.WindowEvent) = publish(WindowClosing(Frame.this)) - def windowDeactivated(e: java.awt.event.WindowEvent) = publish(WindowDeactivated(Frame.this)) - def windowDeiconified(e: java.awt.event.WindowEvent) = publish(WindowDeiconified(Frame.this)) - def windowIconified(e: java.awt.event.WindowEvent) = publish(WindowIconified(Frame.this)) - def windowOpened(e: java.awt.event.WindowEvent) = publish(WindowOpened(Frame.this)) - } - } + + def menuBar: MenuBar = Component.wrapperFor(peer.getJMenuBar) + def menuBar_=(m: MenuBar) = peer.setJMenuBar(m.peer) + + peer.addWindowListener(new java.awt.event.WindowListener { + def windowActivated(e: java.awt.event.WindowEvent) { publish(WindowActivated(Frame.this)) } + def windowClosed(e: java.awt.event.WindowEvent) { publish(WindowClosed(Frame.this)) } + def windowClosing(e: java.awt.event.WindowEvent) { publish(WindowClosing(Frame.this)) } + def windowDeactivated(e: java.awt.event.WindowEvent) { publish(WindowDeactivated(Frame.this)) } + def windowDeiconified(e: java.awt.event.WindowEvent) { publish(WindowDeiconified(Frame.this)) } + def windowIconified(e: java.awt.event.WindowEvent) { publish(WindowIconified(Frame.this)) } + def windowOpened(e: java.awt.event.WindowEvent) { publish(WindowOpened(Frame.this)) } + }) } diff --git a/src/swing/scala/swing/GridBagPanel.scala b/src/swing/scala/swing/GridBagPanel.scala new file mode 100644 index 0000000000..874ad36840 --- /dev/null +++ b/src/swing/scala/swing/GridBagPanel.scala @@ -0,0 +1,80 @@ +package scala.swing + +import java.awt.{Insets, GridBagConstraints} + +object GridBagPanel { + object Fill extends Enumeration { + val None = Value(GridBagConstraints.NONE) + val Horizontal = Value(GridBagConstraints.HORIZONTAL) + val Vertical = Value(GridBagConstraints.VERTICAL) + val Both = Value(GridBagConstraints.BOTH) + } + object Anchor extends Enumeration { + val North = Value(GridBagConstraints.NORTH) + val NorthEast = Value(GridBagConstraints.NORTHEAST) + val East = Value(GridBagConstraints.EAST) + val SouthEast = Value(GridBagConstraints.SOUTHEAST) + val South = Value(GridBagConstraints.SOUTH) + val SouthWest = Value(GridBagConstraints.SOUTHWEST) + val West = Value(GridBagConstraints.WEST) + val NorthWest = Value(GridBagConstraints.NORTHWEST) + val CENTER = Value(GridBagConstraints.CENTER) + + val PageStart = Value(GridBagConstraints.PAGE_START) + val PageEnd = Value(GridBagConstraints.PAGE_END) + val LineStart = Value(GridBagConstraints.LINE_START) + val LineEnd = Value(GridBagConstraints.LINE_END) + val FirstLineStart = Value(GridBagConstraints.FIRST_LINE_START) + val FirstLineEnd = Value(GridBagConstraints.FIRST_LINE_END) + val LastLineStart = Value(GridBagConstraints.LAST_LINE_START) + val LastLineEnd = Value(GridBagConstraints.LAST_LINE_END) + } +} + +class GridBagPanel extends Panel with LayoutContainer { + import GridBagPanel._ + + override lazy val layoutManager = new java.awt.GridBagLayout + override lazy val peer = new javax.swing.JPanel(layoutManager) + + class Constraints(val peer: GridBagConstraints) extends Proxy { + def self = peer + def this(gridx: Int, gridy: Int, + gridwidth: Int, gridheight: Int, + weightx: Double, weighty: Double, + anchor: Int, fill: Int, insets: Insets, + ipadx: Int, ipady: Int) = + this(new GridBagConstraints(gridx, gridy, + gridwidth, gridheight, + weightx, weighty, + anchor, fill, insets, + ipadx, ipady)) + def this() = this(new GridBagConstraints()) + def gridx: Int = peer.gridx + def gridx_=(x: Int) { peer.gridx = x } + def gridy: Int = peer.gridy + def gridy_=(y: Int) { peer.gridy = y } + + def gridwidth: Int = peer.gridwidth + def gridwidth_=(w: Int) { peer.gridwidth = w } + def gridheight: Int = peer.gridheight + def gridheight_=(h: Int) { peer.gridheight = h } + def weightx: Double = peer.weightx + def weightx_=(x: Double) { peer.weightx = x } + def weighty: Double = peer.weighty + def weighty_=(y: Double) { peer.weighty = y } + def anchor: Anchor.Value = Anchor(peer.anchor) + def anchor_=(a: Anchor.Value) { peer.anchor = a.id } + def fill: Fill.Value = Fill(peer.fill) + def fill_=(f: Fill.Value) { peer.fill = f.id } + def insets: Insets = peer.insets + def insets_=(i: Insets) { peer.insets = i } + def ipadx: Int = peer.ipadx + def ipadx_=(x: Int) { peer.ipadx = x } + def ipady: Int = peer.ipady + def ipady_=(y: Int) { peer.ipady = y } + } + + def constraintsFor(comp: Component) = + new Constraints(layoutManager.getConstraints(comp.peer)) +} diff --git a/src/swing/scala/swing/GridPanel.scala b/src/swing/scala/swing/GridPanel.scala index e6360aadbe..799e52d9ae 100644 --- a/src/swing/scala/swing/GridPanel.scala +++ b/src/swing/scala/swing/GridPanel.scala @@ -4,11 +4,17 @@ object GridPanel { val Adapt = 0 } -class GridPanel(rows0: Int, cols0: Int)(content0: Component*) extends IndexedPanel { - override lazy val layout = new java.awt.GridLayout(rows0, cols0) - override lazy val peer = new javax.swing.JPanel(layout) - content ++ content0 +class GridPanel(rows0: Int, cols0: Int) extends Panel with IndexedContainer { + override lazy val layoutManager = new java.awt.GridLayout(rows0, cols0) + override lazy val peer = new javax.swing.JPanel(layoutManager) - def rows: Int = layout.getRows - def columns: Int = layout.getColumns + def rows: Int = layoutManager.getRows + def rows_=(n: Int) { layoutManager.setRows(n) } + def columns: Int = layoutManager.getColumns + def columns_=(n: Int) { layoutManager.setColumns(n) } + + def vGap: Int = layoutManager.getVgap + def vGap_=(n: Int) { layoutManager.setVgap(n) } + def hGap: Int = layoutManager.getHgap + def hGap_=(n: Int) { layoutManager.setHgap(n) } } diff --git a/src/swing/scala/swing/IndexedContainer.scala b/src/swing/scala/swing/IndexedContainer.scala new file mode 100644 index 0000000000..dd38479c17 --- /dev/null +++ b/src/swing/scala/swing/IndexedContainer.scala @@ -0,0 +1,8 @@ +package scala.swing + +import scala.collection.mutable.Buffer + +trait IndexedContainer extends Container { + override val contents: Buffer[Component] = new Content + def contents_=(c: Component*) { contents.clear(); contents ++= c } +} diff --git a/src/swing/scala/swing/IndexedPanel.scala b/src/swing/scala/swing/IndexedPanel.scala deleted file mode 100644 index c2d0034184..0000000000 --- a/src/swing/scala/swing/IndexedPanel.scala +++ /dev/null @@ -1,8 +0,0 @@ -package scala.swing - -import scala.collection.mutable.Buffer - -abstract class IndexedPanel extends Panel { - override val content: Buffer[Component] = new Content - def content_=(c: Component*) { content.clear(); content ++= c } -} diff --git a/src/swing/scala/swing/LayoutContainer.scala b/src/swing/scala/swing/LayoutContainer.scala new file mode 100644 index 0000000000..46cc0e2c10 --- /dev/null +++ b/src/swing/scala/swing/LayoutContainer.scala @@ -0,0 +1,20 @@ +package scala.swing + +import javax.swing.JComponent +import scala.collection.mutable.Map + +trait LayoutContainer extends Container { + type Constraints <: { def peer: AnyRef } + protected def constraintsFor(c: Component): Constraints + def layout: Map[Component, Constraints] = new Map[Component, Constraints] { + def -=(c: Component) { _contents -= c } + def update(c: Component, l: Constraints) { peer.add(c.peer, l.peer) } + def get(c: Component) = Swing.toOption(constraintsFor(c)) + def size = peer.getComponentCount + def elements: Iterator[(Component, Constraints)] = + Iterator.range(0,size).map { c => + val comp = Component.wrapperFor[Component](peer.getComponent(c).asInstanceOf[JComponent]) + (comp, constraintsFor(comp)) + } + } +} diff --git a/src/swing/scala/swing/Menu.scala b/src/swing/scala/swing/Menu.scala new file mode 100644 index 0000000000..fdb75229c1 --- /dev/null +++ b/src/swing/scala/swing/Menu.scala @@ -0,0 +1,40 @@ +package scala.swing + +import scala.collection.mutable._ +import javax.swing._ + +class MenuBar extends IndexedContainer { + override lazy val peer = new JMenuBar + + def menus: Seq[Menu] = contents.filter(_.isInstanceOf[Menu]).map(_.asInstanceOf[Menu]) + + // Not implemented by Swing + //def helpMenu: Menu = Component.wrapperFor(peer.getHelpMenu) + //def helpMenu_=(m: Menu) { peer.setHelpMenu(m.peer) } +} + +/*trait MenuElement extends Component { + def peer: javax.swing.JComponent with javax.swing.MenuElement + + def subElements: Seq[MenuElement] = peer.getSubElements.map(Component.wrapperFor(_)) +}*/ + +class MenuItem(val title: String) extends Button { + def this(a: Action) = { + this("") + action = a + } + override lazy val peer = new JMenuItem(title) +} + +class Menu(title: String) extends MenuItem(title) with IndexedContainer { self: Menu => + override lazy val peer = new JMenu(title) +} + +class RadioMenuItem(title: String) extends MenuItem(title) { + override lazy val peer = new JRadioButtonMenuItem(title) +} + +class CheckMenuItem(title: String) extends MenuItem(title) { + override lazy val peer = new JCheckBoxMenuItem(title) +}
\ No newline at end of file diff --git a/src/swing/scala/swing/Orientation.scala b/src/swing/scala/swing/Orientation.scala index 7b73b15d22..dd38056ccb 100644 --- a/src/swing/scala/swing/Orientation.scala +++ b/src/swing/scala/swing/Orientation.scala @@ -1,6 +1,7 @@ package scala.swing import javax.swing.SwingConstants._ +import javax.swing.JTabbedPane object Orientation { def wrap(n: Int): Orientation = n match { @@ -12,6 +13,19 @@ sealed trait Orientation { def peer: Int } case object Horizontal extends Orientation { def peer = HORIZONTAL } case object Vertical extends Orientation { def peer = VERTICAL } +object Edge { + def wrap(n: Int): Edge = n match { + case LEFT => Left + case RIGHT => Right + case TOP => Top + case BOTTOM => Bottom + } +} + +sealed trait Edge { + def peer: Int +} + object XAlignment { def wrap(n: Int): XAlignment = n match { case LEFT => Left @@ -30,11 +44,11 @@ object YAlignment { } } sealed trait YAlignment { def peer: Int } -case object Left extends XAlignment { def peer = LEFT } -case object Right extends XAlignment { def peer = RIGHT } -case object Top extends YAlignment { def peer = TOP } +case object Left extends XAlignment with Edge { def peer = LEFT } +case object Right extends XAlignment with Edge { def peer = RIGHT } +case object Top extends YAlignment with Edge { def peer = TOP } //case object Baseline extends YAlignment { def peer = BASELINE } -case object Bottom extends YAlignment { def peer = BOTTOM } +case object Bottom extends YAlignment with Edge { def peer = BOTTOM } case object Center extends XAlignment with YAlignment { def peer = CENTER } /*object Orientation extends Enumeration { diff --git a/src/swing/scala/swing/Oriented.scala b/src/swing/scala/swing/Oriented.scala new file mode 100644 index 0000000000..39e2b0ba2a --- /dev/null +++ b/src/swing/scala/swing/Oriented.scala @@ -0,0 +1,13 @@ +package scala.swing + +trait Oriented { + def peer: javax.swing.JComponent { + def getOrientation(): Int + def setOrientation(n: Int) + } + def orientation: Orientation = Orientation.wrap(peer.getOrientation) +} + +trait Orientable extends Oriented { + def orientation_=(o: Orientation) { peer.setOrientation(o.peer) } +} diff --git a/src/swing/scala/swing/Panel.scala b/src/swing/scala/swing/Panel.scala index 40c30dbfd6..5ff6cef0e3 100644 --- a/src/swing/scala/swing/Panel.scala +++ b/src/swing/scala/swing/Panel.scala @@ -3,5 +3,5 @@ package scala.swing abstract class Panel extends Container { override lazy val peer: javax.swing.JPanel = new javax.swing.JPanel - def layout: java.awt.LayoutManager = peer.getLayout + def layoutManager: java.awt.LayoutManager = peer.getLayout } diff --git a/src/swing/scala/swing/ProgressBar.scala b/src/swing/scala/swing/ProgressBar.scala index 07d48f168f..db80035058 100644 --- a/src/swing/scala/swing/ProgressBar.scala +++ b/src/swing/scala/swing/ProgressBar.scala @@ -2,12 +2,9 @@ package scala.swing import event._ -class ProgressBar(override val peer: javax.swing.JProgressBar) extends Component { +class ProgressBar(override val peer: javax.swing.JProgressBar) extends Component with Orientable { def this() = this(new javax.swing.JProgressBar) - def orientation: Orientation = Orientation.wrap(peer.getOrientation) - def orientation_=(o: Orientation) { peer.setOrientation(o.peer) } - def min: Int = peer.getMinimum def min_=(v: Int) { peer.setMinimum(v) } def max: Int = peer.getMaximum diff --git a/src/swing/scala/swing/PushButton.scala b/src/swing/scala/swing/PushButton.scala new file mode 100644 index 0000000000..99e08e4e72 --- /dev/null +++ b/src/swing/scala/swing/PushButton.scala @@ -0,0 +1,15 @@ +package scala.swing + +import javax.swing._ +import event._ + +/** A class for buttons; standard constructor wraps around a swing button */ +class PushButton(override val peer: JButton) extends Component with Publisher { + def this(txt: String) = this(new JButton(txt)) + def this() = this(new JButton) + def text: String = peer.getText + def text_=(s: String) = peer.setText(s) + def icon: Icon = peer.getIcon + def icon_=(i: Icon) = peer.setIcon(i) + +} diff --git a/src/swing/scala/swing/RadioButton.scala b/src/swing/scala/swing/RadioButton.scala new file mode 100644 index 0000000000..4b0cd50087 --- /dev/null +++ b/src/swing/scala/swing/RadioButton.scala @@ -0,0 +1,8 @@ +package scala.swing + +import javax.swing._ + +class RadioButton(override val peer: JRadioButton) extends ToggleButton(peer) { + def this(txt: String) = this(new JRadioButton(txt)) + def this() = this(new JRadioButton) +}
\ No newline at end of file diff --git a/src/swing/scala/swing/Reactions.scala b/src/swing/scala/swing/Reactions.scala index af2ca7e2fa..7b94650976 100644 --- a/src/swing/scala/swing/Reactions.scala +++ b/src/swing/scala/swing/Reactions.scala @@ -21,7 +21,8 @@ class Reactions { def sendTo(ps: List[Reaction]): Unit = ps match { case Nil => case p :: ps => - if (p isDefinedAt e) p(e) else sendTo(ps) + if (p isDefinedAt e) p(e) + /*else*/ sendTo(ps) } sendTo(parts) } diff --git a/src/swing/scala/swing/ScrollPane.scala b/src/swing/scala/swing/ScrollPane.scala index c794372edc..17fb5e8190 100644 --- a/src/swing/scala/swing/ScrollPane.scala +++ b/src/swing/scala/swing/ScrollPane.scala @@ -2,7 +2,7 @@ package scala.swing import javax.swing.JScrollPane -class ScrollPane(override val peer: JScrollPane) extends Container(peer) with Publisher { +class ScrollPane(override val peer: JScrollPane) extends Component with Publisher { def this() = this(new JScrollPane) def this(contents: Component) = this(new JScrollPane(contents.peer)) diff --git a/src/swing/scala/swing/Scrollable.scala b/src/swing/scala/swing/Scrollable.scala new file mode 100644 index 0000000000..d5ffe636b6 --- /dev/null +++ b/src/swing/scala/swing/Scrollable.scala @@ -0,0 +1,17 @@ +package scala.swing + +import geometry._ + +trait Scrollable extends Component { + protected def scrollablePeer: javax.swing.Scrollable + def preferredViewportSize = scrollablePeer.getPreferredScrollableViewportSize + + def tracksViewportHeight: Boolean = scrollablePeer.getScrollableTracksViewportHeight + def tracksViewportWidth: Boolean = scrollablePeer.getScrollableTracksViewportWidth + + def blockIncrement(visibleRect: Rectangle, orientation: Orientation, direction: Int): Int = + scrollablePeer.getScrollableBlockIncrement(visibleRect.peer, orientation.peer, direction) + + def unitIncrement(visibleRect: Rectangle, orientation: Orientation, direction: Int): Int = + scrollablePeer.getScrollableUnitIncrement(visibleRect.peer, orientation.peer, direction) +} diff --git a/src/swing/scala/swing/Selectable.scala b/src/swing/scala/swing/Selectable.scala new file mode 100644 index 0000000000..38b86efb60 --- /dev/null +++ b/src/swing/scala/swing/Selectable.scala @@ -0,0 +1,11 @@ +package scala.swing + +trait Selectable { + def peer: javax.swing.JComponent { + def setSelected(b: Boolean) + def isSelected(): Boolean + } + + def selected: Boolean = peer.isSelected + def selected_=(b: Boolean) = peer.setSelected(b) +} diff --git a/src/swing/scala/swing/Separator.scala b/src/swing/scala/swing/Separator.scala new file mode 100644 index 0000000000..3be204a49f --- /dev/null +++ b/src/swing/scala/swing/Separator.scala @@ -0,0 +1,10 @@ +package scala.swing + +import javax.swing._ + +/** + * @see javax.swing.JSeparator + */ +class Separator extends Component with Oriented { + override lazy val peer = new JSeparator +} diff --git a/src/swing/scala/swing/SimpleGUIApplication.scala b/src/swing/scala/swing/SimpleGUIApplication.scala index efbe580116..8995852b79 100644 --- a/src/swing/scala/swing/SimpleGUIApplication.scala +++ b/src/swing/scala/swing/SimpleGUIApplication.scala @@ -7,7 +7,7 @@ abstract class SimpleGUIApplication extends GUIApplication { def main(args: Array[String]) = { SwingUtilities.invokeLater { - new Runnable { def run() { init(); top.pack.show() } } + new Runnable { def run() { init(); top.pack().show() } } } } diff --git a/src/swing/scala/swing/Slider.scala b/src/swing/scala/swing/Slider.scala index e4927709ca..0c0e4894a8 100644 --- a/src/swing/scala/swing/Slider.scala +++ b/src/swing/scala/swing/Slider.scala @@ -3,12 +3,9 @@ package scala.swing import event._ import Swing._ -class Slider(override val peer: javax.swing.JSlider) extends Component with EditorComponent { +class Slider(override val peer: javax.swing.JSlider) extends Component with Orientable with EditorComponent { def this() = this(new javax.swing.JSlider) - def orientation: Orientation = Orientation.wrap(peer.getOrientation) - def orientation_=(o: Orientation) { peer.setOrientation(o.peer) } - def min: Int = peer.getMinimum def min_=(v: Int) { peer.setMinimum(v) } def max: Int = peer.getMaximum diff --git a/src/swing/scala/swing/Swing.scala b/src/swing/scala/swing/Swing.scala index 781e399794..f1dcfc7ebb 100644 --- a/src/swing/scala/swing/Swing.scala +++ b/src/swing/scala/swing/Swing.scala @@ -1,9 +1,14 @@ package scala.swing +import geometry._ import javax.swing._ import javax.swing.event._ object Swing { + protected[swing] def ifNull[A](o: Object, a: A): A = if(o eq null) a else o.asInstanceOf[A] + protected[swing] def toOption[A](o: Object): Option[A] = if(o eq null) None else Some(o.asInstanceOf[A]) + protected[swing] def toNull[A>:Null<:AnyRef](a: Option[A]): Object = if(a == None) null else a.get + implicit def block2Runnable(block: =>Unit): Runnable = new Runnable { override def run = block } diff --git a/src/swing/scala/swing/TabbedPane.scala b/src/swing/scala/swing/TabbedPane.scala new file mode 100644 index 0000000000..e3ff3ecc34 --- /dev/null +++ b/src/swing/scala/swing/TabbedPane.scala @@ -0,0 +1,76 @@ +package scala.swing + +import geometry._ +import scala.collection.mutable.Buffer +import javax.swing.{JTabbedPane, JComponent} + + +object TabbedPane { + object Layout extends Enumeration { + val Wrap = Value(JTabbedPane.WRAP_TAB_LAYOUT) + val Scroll = Value(JTabbedPane.SCROLL_TAB_LAYOUT) + } +} + +class TabbedPane(override val peer: JTabbedPane) extends Component with Publisher { + import TabbedPane._ + + class Tab protected(title0: String, component0: Component, tip0: String, index0: Int) { + def this(title0: String, component0: Component, tip0: String) = + this(title0, component0, tip0, 0) + title = title0 + component = component0 + tip = tip0 + def title: String = peer.getTitleAt(index) + def title_=(t: String) { peer.setTitleAt(index, t) } + def component: Component = Component.wrapperFor(peer.getComponentAt(index).asInstanceOf[JComponent]) + def component_=(c: Component) { peer.setComponentAt(index, c.peer) } + def tip: String = peer.getToolTipTextAt(index) + def tip_=(t: String) { peer.setToolTipTextAt(index, t) } + def enabled: Boolean = peer.isEnabledAt(index) + def enabled_=(b: Boolean) { peer.setEnabledAt(index, b) } + def mnemonic: Int = peer.getMnemonicAt(index) + def mnemonic_=(k: Int) = peer.setMnemonicAt(index, k) + def foreground: Color = new Color(peer.getForegroundAt(index)) + def foreground_=(c: Color) = peer.setForegroundAt(index, c) + def background: Color = new Color(peer.getBackgroundAt(index)) + def background_=(c: Color) = peer.setBackgroundAt(index, c) + def bounds: Rectangle = Rectangle.wrap(peer.getBoundsAt(index)) + + // TODO: icon, disabledIcon + + def index = _index + protected[TabbedPane] var _index: Int = index0 + } + + def this() = this(new JTabbedPane) + + object tabs extends BufferAdapter[Tab] { + def runCount: Int = peer.getTabRunCount + + def remove(n: Int): Tab = { + val t = apply(n) + peer.removeTabAt(n) + for(i <- n to length) apply(i)._index -= 1 + t + } + protected def insertAt(n: Int, t: Tab) { + for(i <- n to length) apply(i)._index += 1 + peer.insertTab(t.title, null, t.component.peer, t.tip, n) + } + + def +=(t: Tab) { peer.addTab(t.title, null, t.component.peer, t.tip) } + def length = peer.getTabCount + def apply(n: Int) = new Tab(peer.getTitleAt(n), + Component.wrapperFor(peer.getComponentAt(n).asInstanceOf[javax.swing.JComponent]), + peer.getToolTipTextAt(n)) + } + + def tabLayoutPolicy: Layout.Value = Layout(peer.getTabLayoutPolicy) + def tabLayoutPolicy_=(p: Layout.Value) { peer.setTabLayoutPolicy(p.id) } + + def tabPlacement: Edge = Edge.wrap(peer.getTabPlacement) + def tabPlacement(b: Edge) { peer.setTabPlacement(b.peer) } + + def selected: Tab = tabs(peer.getSelectedIndex) +} diff --git a/src/swing/scala/swing/Table.scala b/src/swing/scala/swing/Table.scala index 7358928568..a9078f26aa 100644 --- a/src/swing/scala/swing/Table.scala +++ b/src/swing/scala/swing/Table.scala @@ -1,10 +1,12 @@ package scala.swing +import geometry._ import model.Matrix import javax.swing._ import javax.swing.table._ import javax.swing.event._ import event._ +import scala.collection.mutable.Set object Table { object AutoResizeMode extends Enumeration { @@ -15,9 +17,18 @@ object Table { val LastColumn = Value(AUTO_RESIZE_LAST_COLUMN, "LastColumn") val AllColumns = Value(AUTO_RESIZE_ALL_COLUMNS, "AllColumns") } + + object IntervalMode extends Enumeration { + val Single = Value(ListSelectionModel.SINGLE_SELECTION) + val SingleInterval = Value(ListSelectionModel.SINGLE_INTERVAL_SELECTION) + val MultiInterval = Value(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION) + } + object ElementMode extends Enumeration { + val Row, Column, Cell, None = Value + } } -class Table(override val peer: JTable) extends Component with Publisher { +class Table(override val peer: JTable) extends Component with Scrollable with Publisher { import Table._ def this() = this(new JTable()) def this(numRows: Int, numColumns: Int) = this(new JTable(numRows, numColumns)) @@ -28,6 +39,8 @@ class Table(override val peer: JTable) extends Component with Publisher { def this(dm: TableModel, cm: TableColumnModel) = this(new JTable(dm, cm)) def this(dm: TableModel, cm: TableColumnModel, sm: ListSelectionModel) = this(new JTable(dm, cm, sm)) + protected def scrollablePeer = peer + def rowHeight = peer.getRowHeight def rowHeight_=(x: Int) = peer.setRowHeight(x) @@ -45,8 +58,89 @@ class Table(override val peer: JTable) extends Component with Publisher { def gridColor = new swing.Color(peer.getGridColor) def gridColor_=(color: swing.Color) = peer.setGridColor(color) + def preferredViewportSize_=(dim: Dimension) = peer.setPreferredScrollableViewportSize(dim.peer) + def fillsViewportHeight: Boolean = peer.getFillsViewportHeight + def fillsViewportHeight_=(b: Boolean) = peer.setFillsViewportHeight(b) + + // TODO: could be a sorted set + protected abstract class SelectionSet[A](a: =>Seq[A]) extends Set[A] { + def -=(n: A) + def +=(n: A) + def contains(n: A) = a.contains(n) + def size = a.length + def elements = a.elements + } + + class Selection extends Publisher { + object rows extends SelectionSet(peer.getSelectedRows) { + def -=(n: Int) { peer.removeRowSelectionInterval(n,n) } + def +=(n: Int) { peer.addRowSelectionInterval(n,n) } + + def leadIndex: Int = peer.getSelectionModel.getLeadSelectionIndex + def anchorIndex: Int = peer.getSelectionModel.getAnchorSelectionIndex + } + + object columns extends SelectionSet(peer.getSelectedColumns) { + def -=(n: Int) { peer.removeColumnSelectionInterval(n,n) } + def +=(n: Int) { peer.addColumnSelectionInterval(n,n) } + + def leadIndex: Int = peer.getColumnModel.getSelectionModel.getLeadSelectionIndex + def anchorIndex: Int = peer.getColumnModel.getSelectionModel.getAnchorSelectionIndex + } + + def cells: Set[(Int, Int)] = + new SelectionSet[(Int, Int)]((for(r <- selection.rows; c <- selection.columns) yield (r,c)).toSeq) { outer => + def -=(n: (Int, Int)) { + peer.removeRowSelectionInterval(n._1,n._1) + peer.removeColumnSelectionInterval(n._2,n._2) + } + def +=(n: (Int, Int)) { + peer.addRowSelectionInterval(n._1,n._1) + peer.addColumnSelectionInterval(n._2,n._2) + } + override def size = peer.getSelectedRowCount * peer.getSelectedColumnCount + } + + /** + * From the JTable Swing tutorial: + * You can specify selection by cell in multiple interval selection mode, + * but the result is a table that does not produce useful selections. + */ + def intervalMode: IntervalMode.Value = IntervalMode(peer.getSelectionModel.getSelectionMode) + def intervalMode_=(m: IntervalMode.Value) { peer.getSelectionModel.setSelectionMode(m.id) } + def elementMode: ElementMode.Value = + if(peer.getColumnSelectionAllowed && peer.getRowSelectionAllowed) ElementMode.Cell + else if(peer.getColumnSelectionAllowed) ElementMode.Column + else if(peer.getRowSelectionAllowed) ElementMode.Row + else ElementMode.None + def elementMode_=(m: ElementMode.Value) { + m match { + case ElementMode.Cell => peer.setCellSelectionEnabled(true) + case ElementMode.Column => peer.setRowSelectionAllowed(false); peer.setColumnSelectionAllowed(true) + case ElementMode.Row => peer.setRowSelectionAllowed(true); peer.setColumnSelectionAllowed(false) + case ElementMode.None => peer.setRowSelectionAllowed(false); peer.setColumnSelectionAllowed(false) + } + } + + peer.getColumnModel.getSelectionModel.addListSelectionListener(new ListSelectionListener { + def valueChanged(e: ListSelectionEvent) { + publish(ColumnsSelected(Table.this, e.getValueIsAdjusting, e.getFirstIndex to e.getLastIndex)) + } + }) + peer.getSelectionModel.addListSelectionListener(new ListSelectionListener { + def valueChanged(e: ListSelectionEvent) { + publish(RowsSelected(Table.this, e.getValueIsAdjusting, e.getFirstIndex to e.getLastIndex)) + } + }) + } + + val selection: Selection = new Selection + private val initialRenderer = peer.getDefaultRenderer(classOf[AnyRef]) + /** + * Supplies a renderer component for a given cell. + */ protected def render(isSelected: Boolean, hasFocus: Boolean, row: Int, column: Int): Component = new Component { override lazy val peer = initialRenderer.getTableCellRendererComponent(Table.this.peer, @@ -54,9 +148,9 @@ class Table(override val peer: JTable) extends Component with Publisher { } peer.setDefaultRenderer(classOf[AnyRef], new TableCellRenderer { - def getTableCellRendererComponent(table: JTable, value: AnyRef, isSelected: Boolean, hasFocus: Boolean, row: Int, column: Int) = - render(isSelected, hasFocus, row, column).peer - }) + def getTableCellRendererComponent(tabBlockIle: JTable, value: AnyRef, isSelected: Boolean, hasFocus: Boolean, row: Int, column: Int) = + render(isSelected, hasFocus, row, column).peer + }) def apply(row: Int, column: Int) = peer.getValueAt(row, column) def update(row: Int, column: Int, value: AnyRef) = peer.setValueAt(value, row, column) diff --git a/src/swing/scala/swing/TextArea.scala b/src/swing/scala/swing/TextArea.scala new file mode 100644 index 0000000000..396f218d30 --- /dev/null +++ b/src/swing/scala/swing/TextArea.scala @@ -0,0 +1,31 @@ +package scala.swing + +import javax.swing._ +import java.awt.event._ +import event._ + +class TextArea(override val peer: JTextArea) extends TextComponent(peer) with TextComponent.HasColumns with TextComponent.HasRows { + def this(text: String, rows: Int, columns: int) = this(new JTextArea(text, rows, columns)) + def this(text: String) = this(new JTextArea(text)) + def this(rows: Int, columns: int) = this(new JTextArea(rows, columns)) + def this() = this(new JTextArea()) + + // TODO: we could make contents StringBuilder-like + def append(t: String) { peer.append(t) } + + def rows: Int = peer.getRows + def rows_=(n: Int) = peer.setRows(n) + def columns: Int = peer.getColumns + def columns_=(n: Int) = peer.setColumns(n) + + def tabSize: Int = peer.getTabSize + def tabSize_=(n: Int) = peer.setTabSize(n) + def lineCount: Int = peer.getLineCount + + def lineWrap: Boolean = peer.getLineWrap + def lineWrap_=(w: Boolean) = peer.setLineWrap(w) + def wordWrap: Boolean = peer.getWrapStyleWord + def wordWrap_=(w: Boolean) = peer.setWrapStyleWord(w) + def charWrap: Boolean = !peer.getWrapStyleWord + def charWrap_=(w: Boolean) = peer.setWrapStyleWord(!w) +}
\ No newline at end of file diff --git a/src/swing/scala/swing/TextComponent.scala b/src/swing/scala/swing/TextComponent.scala index ae496a5ba5..fb06cb4023 100644 --- a/src/swing/scala/swing/TextComponent.scala +++ b/src/swing/scala/swing/TextComponent.scala @@ -5,14 +5,29 @@ import javax.swing.text._ import javax.swing.event._ import event._ +object TextComponent { + trait HasColumns extends TextComponent { + def columns: Int + def columns_=(n: Int) + } + trait HasRows extends TextComponent { + def rows: Int + def rows_=(n: Int) + } +} + class TextComponent(override val peer: JTextComponent) extends Component with EditorComponent with Publisher { - def text: String = peer.getText - def text_=(x: String) = peer.setText(x) + def contents: String = peer.getText + def contents_=(t: String) = peer.setText(t) val caret = new Caret(peer.getCaret) - def content: String = peer.getText - def content_=(v: String) { peer.setText(v) } + def editable: Boolean = peer.isEditable + def editable_=(x: Boolean) = peer.setEditable(x) + + def cut() { peer.cut() } + def copy() { peer.copy() } + def selected: String = peer.getSelectedText peer.addCaretListener { new CaretListener { diff --git a/src/swing/scala/swing/TextField.scala b/src/swing/scala/swing/TextField.scala index 7604d2719b..9658230608 100644 --- a/src/swing/scala/swing/TextField.scala +++ b/src/swing/scala/swing/TextField.scala @@ -4,14 +4,14 @@ import javax.swing._ import java.awt.event._ import event._ -class TextField(override val peer: JTextField) extends TextComponent(peer) { +class TextField(override val peer: JTextField) extends TextComponent(peer) with TextComponent.HasColumns { def this(text: String, columns: int) = this(new JTextField(text, columns)) def this(text: String) = this(new JTextField(text)) def this(columns: int) = this(new JTextField(columns)) def this() = this(new JTextField()) - def columns: int = peer.getColumns() - def columns_=(x: int) = peer.setColumns(x) + def columns: Int = peer.getColumns + def columns_=(n: Int) = peer.setColumns(n) override lazy val contentModified = new Publisher { peer.addActionListener { diff --git a/src/swing/scala/swing/ToggleButton.scala b/src/swing/scala/swing/ToggleButton.scala new file mode 100644 index 0000000000..eebf3f3675 --- /dev/null +++ b/src/swing/scala/swing/ToggleButton.scala @@ -0,0 +1,9 @@ +package scala.swing + +import javax.swing._ +import event._ + +class ToggleButton(override val peer: JToggleButton) extends Button(peer) { + def this(txt: String) = this(new JToggleButton(txt)) + def this() = this(new JToggleButton) +}
\ No newline at end of file diff --git a/src/swing/scala/swing/event/ButtonClicked.scala b/src/swing/scala/swing/event/ButtonClicked.scala new file mode 100644 index 0000000000..cf826a6ff6 --- /dev/null +++ b/src/swing/scala/swing/event/ButtonClicked.scala @@ -0,0 +1,4 @@ +package scala.swing.event + +case class ButtonClicked(override val source: Button) extends ComponentEvent(source) + diff --git a/src/swing/scala/swing/event/ButtonPressed.scala b/src/swing/scala/swing/event/ButtonPressed.scala deleted file mode 100644 index b0d7dc05c9..0000000000 --- a/src/swing/scala/swing/event/ButtonPressed.scala +++ /dev/null @@ -1,3 +0,0 @@ -package scala.swing.event - -case class ButtonPressed(override val source: Button) extends ComponentEvent(source) diff --git a/src/swing/scala/swing/event/LiveEvent.scala b/src/swing/scala/swing/event/LiveEvent.scala new file mode 100644 index 0000000000..a68a616f90 --- /dev/null +++ b/src/swing/scala/swing/event/LiveEvent.scala @@ -0,0 +1,5 @@ +package scala.swing.event + +trait LiveEvent { + def live: Boolean +} diff --git a/src/swing/scala/swing/event/MouseEvent.scala b/src/swing/scala/swing/event/MouseEvent.scala index 52f6731d1a..20a520c3a6 100644 --- a/src/swing/scala/swing/event/MouseEvent.scala +++ b/src/swing/scala/swing/event/MouseEvent.scala @@ -1,5 +1,7 @@ package scala.swing.event +import geometry._ + class MouseEvent(source: Component, point: Point, modifiers: Int) extends ComponentEvent(source) class MouseButtonEvent(source: Component, point: Point, modifiers: Int, diff --git a/src/swing/scala/swing/event/SelectionEvent.scala b/src/swing/scala/swing/event/SelectionEvent.scala new file mode 100644 index 0000000000..5fea0a6f57 --- /dev/null +++ b/src/swing/scala/swing/event/SelectionEvent.scala @@ -0,0 +1,5 @@ +package scala.swing.event + +trait SelectionEvent { + def range: Range +} diff --git a/src/swing/scala/swing/event/TableChanged.scala b/src/swing/scala/swing/event/TableChanged.scala deleted file mode 100644 index 92a6cd5881..0000000000 --- a/src/swing/scala/swing/event/TableChanged.scala +++ /dev/null @@ -1,5 +0,0 @@ -package scala.swing.event - -case class TableChanged(override val source: Table, firstRow: Int, lastRow: Int, column: Int) extends ComponentEvent(source) { - println("table changed: "+source+"/"+firstRow+"-"+lastRow+":"+column) -} diff --git a/src/swing/scala/swing/event/TableEvent.scala b/src/swing/scala/swing/event/TableEvent.scala new file mode 100644 index 0000000000..4a556fed20 --- /dev/null +++ b/src/swing/scala/swing/event/TableEvent.scala @@ -0,0 +1,10 @@ +package scala.swing.event + +class TableEvent(override val source: Table) extends ComponentEvent(source) + +case class TableChanged(override val source: Table, firstRow: Int, lastRow: Int, column: Int) extends TableEvent(source) +case class TableResized(override val source: Table) extends TableEvent(source) +//case class TextModified(override val source: TextComponent) extends ContentModified(source) + +case class ColumnsSelected(override val source: Table, live: Boolean, range: Range) extends TableEvent(source) with LiveEvent with SelectionEvent +case class RowsSelected(override val source: Table, live: Boolean, range: Range) extends TableEvent(source) with LiveEvent with SelectionEvent
\ No newline at end of file diff --git a/src/swing/scala/swing/event/TableResized.scala b/src/swing/scala/swing/event/TableResized.scala deleted file mode 100644 index c2d03dfa91..0000000000 --- a/src/swing/scala/swing/event/TableResized.scala +++ /dev/null @@ -1,3 +0,0 @@ -package scala.swing.event - -case class TableResized(override val source: Table) extends ComponentEvent(source) diff --git a/src/swing/scala/swing/Dimension.scala b/src/swing/scala/swing/geometry/Dimension.scala index 872f2022b2..abe48f8c0a 100644 --- a/src/swing/scala/swing/Dimension.scala +++ b/src/swing/scala/swing/geometry/Dimension.scala @@ -1,4 +1,4 @@ -package scala.swing +package scala.swing.geometry object Dimension { def apply(w: Int, h: Int) = new Dimension { diff --git a/src/swing/scala/swing/Point.scala b/src/swing/scala/swing/geometry/Point.scala index 953f6bf3ab..352afb5985 100644 --- a/src/swing/scala/swing/Point.scala +++ b/src/swing/scala/swing/geometry/Point.scala @@ -1,4 +1,4 @@ -package scala.swing +package scala.swing.geometry object Point { def apply(p: java.awt.Point) = new Point(p.getX, p.getY) diff --git a/src/swing/scala/swing/geometry/Rectangle.scala b/src/swing/scala/swing/geometry/Rectangle.scala new file mode 100644 index 0000000000..707c99a3a1 --- /dev/null +++ b/src/swing/scala/swing/geometry/Rectangle.scala @@ -0,0 +1,19 @@ +package scala.swing.geometry + +object Rectangle { + def apply(x: Int, y: Int, w: Int, h: Int) = new Rectangle { + lazy val peer: java.awt.Rectangle = new java.awt.Rectangle(x, y, w, h) + } + + def wrap(rect: java.awt.Rectangle) = new Rectangle { + def peer: java.awt.Rectangle = rect + } +} + +abstract class Rectangle { + def peer: java.awt.Rectangle + def width = peer.getWidth + def height = peer.getHeight + def x = peer.x + def y = peer.y +} diff --git a/src/swing/scala/swing/model/Matrix.scala b/src/swing/scala/swing/model/Matrix.scala index 6342d65dc7..a578452fd2 100644 --- a/src/swing/scala/swing/model/Matrix.scala +++ b/src/swing/scala/swing/model/Matrix.scala @@ -1,6 +1,6 @@ package scala.swing.model -trait Matrix[A]extends Function2[Int, Int, A] { +trait Matrix[A] extends Function2[Int, Int, A] { val width: Int val height: Int diff --git a/src/swing/scala/swing/test/CelsiusConverter.scala b/src/swing/scala/swing/test/CelsiusConverter.scala index b1aef5f077..9cd6092f31 100644 --- a/src/swing/scala/swing/test/CelsiusConverter.scala +++ b/src/swing/scala/swing/test/CelsiusConverter.scala @@ -14,7 +14,7 @@ object CelsiusConverter extends SimpleGUIApplication { text = "Celsius" border = EmptyBorder(5, 5, 5, 5) } - object convertButton extends Button { + object convertButton extends PushButton { icon = new javax.swing.ImageIcon("c:\\workspace\\gui\\images\\convert.gif") border = EmptyBorder(5, 5, 5, 5) } @@ -23,13 +23,14 @@ object CelsiusConverter extends SimpleGUIApplication { border = EmptyBorder(5, 5, 5, 5) listenTo(convertButton, tempCelsius) reactions += { - case ButtonPressed(_) | ContentModified(_) => - val c = Integer.parseInt(tempCelsius.text) + case ButtonClicked(_) | ContentModified(_) => + val c = Integer.parseInt(tempCelsius.contents) val f = c * 9 / 5 + 32 text = "<html><font color = red>"+f+"</font> Fahrenheit</html>" } } - content = new GridPanel(2,2)(tempCelsius, celsiusLabel, convertButton, fahrenheitLabel) { + content = new GridPanel(2,2) { + contents.append(tempCelsius, celsiusLabel, convertButton, fahrenheitLabel) border = EmptyBorder(10, 10, 10, 10) } } diff --git a/src/swing/scala/swing/test/CelsiusConverter2.scala b/src/swing/scala/swing/test/CelsiusConverter2.scala index d19ce9e4e4..5b8af8f5c0 100644 --- a/src/swing/scala/swing/test/CelsiusConverter2.scala +++ b/src/swing/scala/swing/test/CelsiusConverter2.scala @@ -8,20 +8,20 @@ object CelsiusConverter2 extends SimpleGUIApplication { title = "Convert Celsius / Fahrenheit" object Celsius extends TextField { columns = 5 } object Fahrenheit extends TextField { columns = 5 } - content = new FlowPanel(Horizontal)(Celsius, new Label(" Celsius = "), - Fahrenheit, new Label(" Fahrenheit")) { + content = new FlowPanel { + contents.append(Celsius, new Label(" Celsius = "), Fahrenheit, new Label(" Fahrenheit")) border = EmptyBorder(15, 10, 10, 10) } listenTo(Fahrenheit.contentModified, Celsius.contentModified) reactions += { case ContentModified(Fahrenheit) => - val f = Integer.parseInt(Fahrenheit.text) + val f = Integer.parseInt(Fahrenheit.contents) val c = (f - 32) * 5 / 9 - Celsius.text = c.toString + Celsius.contents = c.toString case ContentModified(Celsius) => - val c = Integer.parseInt(Celsius.text) + val c = Integer.parseInt(Celsius.contents) val f = c * 9 / 5 + 32 - Fahrenheit.text = f.toString + Fahrenheit.contents = f.toString } } } diff --git a/src/swing/scala/swing/test/GridBagDemo.scala b/src/swing/scala/swing/test/GridBagDemo.scala new file mode 100644 index 0000000000..2131d0c82e --- /dev/null +++ b/src/swing/scala/swing/test/GridBagDemo.scala @@ -0,0 +1,62 @@ +package scala.swing.test + +import swing._ +import swing.event._ +import GridBagPanel._ +import java.awt.Insets + +object GridBagDemo extends SimpleGUIApplication { + def top = new MainFrame { + title = "GridBag Demo" + content = new GridBagPanel { + val c = new Constraints + val shouldFill = true + if (shouldFill) { + c.fill = Fill.Horizontal + } + + val button1 = new PushButton("Button 1") + + c.weightx = 0.5 + + c.fill = Fill.Horizontal + c.gridx = 0; + c.gridy = 0; + layout(button1) = c + + val button2 = new PushButton("Button 2") + c.fill = Fill.Horizontal + c.weightx = 0.5; + c.gridx = 1; + c.gridy = 0; + layout(button2) = c + + val button3 = new PushButton("Button 3") + c.fill = Fill.Horizontal + c.weightx = 0.5; + c.gridx = 2; + c.gridy = 0; + layout(button3) = c + + val button4 = new PushButton("Long-Named Button 4") + c.fill = Fill.Horizontal + c.ipady = 40; //make this component tall + c.weightx = 0.0; + c.gridwidth = 3; + c.gridx = 0; + c.gridy = 1; + layout(button4) = c + + val button5 = new PushButton("5") + c.fill = Fill.Horizontal + c.ipady = 0; //reset to default + c.weighty = 1.0; //request any extra vertical space + c.anchor = Anchor.PageEnd + c.insets = new Insets(10,0,0,0); //top padding + c.gridx = 1; //aligned with button 2 + c.gridwidth = 2; //2 columns wide + c.gridy = 2; //third row + layout(button5) = c + } + } +}
\ No newline at end of file diff --git a/src/swing/scala/swing/test/MenuDemo.scala b/src/swing/scala/swing/test/MenuDemo.scala new file mode 100644 index 0000000000..fb407503d5 --- /dev/null +++ b/src/swing/scala/swing/test/MenuDemo.scala @@ -0,0 +1,32 @@ +package scala.swing.test + +import swing._ +import swing.event._ + +object MenuDemo extends SimpleGUIApplication { + def top = new MainFrame { + title = "Menu Demo" + menuBar = new MenuBar + + implicit def action2MenuItem(a: Action): MenuItem = new MenuItem(a) + + val menu = new Menu("A Menu") + menu.contents += new MenuItem("An item") + menu.contents += new Action("An action item") { + def apply() { println("Action '"+ title +"' invoked") } + } + menu.contents += new Separator + menu.contents += new CheckMenuItem("Check me") + menu.contents += new CheckMenuItem("Me too!") + menu.contents += new Separator + val a = new RadioMenuItem("a") + val b = new RadioMenuItem("b") + val c = new RadioMenuItem("b") + val mutex = new ButtonMutex(a,b,c) + menu.contents ++= mutex.buttons + + menuBar.contents += menu + menuBar.contents += new Menu("Empty Menu") + } +} + diff --git a/src/swing/scala/swing/test/SimpleApplet.scala b/src/swing/scala/swing/test/SimpleApplet.scala index c42bc873eb..f072a617d6 100644 --- a/src/swing/scala/swing/test/SimpleApplet.scala +++ b/src/swing/scala/swing/test/SimpleApplet.scala @@ -5,15 +5,15 @@ import event._ class SimpleApplet extends Applet { object ui extends UI with Reactor { def init() = { - val button = new Button("Press here!") + val button = new PushButton("Press here!") val text = new TextField("Java Version: " + System.getProperty("java.version")+"\n") listenTo(button) reactions += { - case ButtonPressed(_) => text.content += "Button Pressed!\n" + case ButtonClicked(_) => text.contents += "Button Pressed!\n" case _ => } - content = new BoxPanel(Vertical)(button, text) + content = new BoxPanel(Vertical) { contents.append(button, text) } } } }
\ No newline at end of file diff --git a/src/swing/scala/swing/test/SwingApp.scala b/src/swing/scala/swing/test/SwingApp.scala index 3be407411a..5560c74f59 100644 --- a/src/swing/scala/swing/test/SwingApp.scala +++ b/src/swing/scala/swing/test/SwingApp.scala @@ -12,15 +12,16 @@ object SwingApp extends SimpleGUIApplication { text = prefix + "0 " listenTo(button) reactions += { - case ButtonPressed(button) => + case ButtonClicked(button) => numclicks = numclicks + 1 text = prefix + numclicks } } - object button extends Button { + object button extends PushButton { text = "I am a button" } - content = new GridPanel(GridPanel.Adapt,1)(label, button) { + content = new GridPanel(GridPanel.Adapt,1) { + contents.append(label, button) border = EmptyBorder(5, 5, 5, 5) } } diff --git a/src/swing/scala/swing/test/TableSelection.scala b/src/swing/scala/swing/test/TableSelection.scala new file mode 100644 index 0000000000..2e454144dd --- /dev/null +++ b/src/swing/scala/swing/test/TableSelection.scala @@ -0,0 +1,99 @@ +package scala.swing.test + +import swing._ +import swing.event._ +import swing.geometry._ + +object TableSelection extends SimpleGUIApplication { + def top = new MainFrame { + title = "Table Selection" + + val model = Array[Array[AnyRef]](Array[AnyRef]("Mary", "Campione", "Snowboarding", new java.lang.Integer(5), new java.lang.Boolean(false)), + Array[AnyRef]("Alison", "Huml", "Rowing", new java.lang.Integer(5), new java.lang.Boolean(false)), + Array[AnyRef]("Kathy", "Walrath", "Knitting", new java.lang.Integer(5), new java.lang.Boolean(false)), + Array[AnyRef]("Sharon", "Zakhour", "Speed reading", new java.lang.Integer(5), new java.lang.Boolean(false)), + Array[AnyRef]("Philip", "Milne", "Pool", new java.lang.Integer(5), new java.lang.Boolean(false))) + + content = new BoxPanel(Vertical) { + val table = new Table(model, Array[AnyRef]("First Name", "Last Name", "Sport", "# of Years", "Vegetarian")) + listenTo() + table.preferredViewportSize = Dimension(500, 70) + table.fillsViewportHeight = true + listenTo(table.selection) + + contents += new ScrollPane(table) + + contents += new Label("Selection Mode") + val intervalMutex = new ButtonMutex + def radio(mutex: ButtonMutex, text: String): RadioButton = { + val b = new RadioButton(text) + listenTo(b) + mutex.buttons += b + contents += b + b + } + val multiInterval = radio(intervalMutex, "Multiple Interval Selection") + val elementInterval = radio(intervalMutex, "Single Selection") + val singleInterval = radio(intervalMutex, "Single Interval Selection") + + contents += new Label("Selection Options") + val elemMutex = new ButtonMutex + val rowSelection = radio(elemMutex, "Row Selection") + val columnSelection = radio(elemMutex, "Column Selection") + val cellSelection = radio(elemMutex, "Cell Selection") + + val output = new TextArea(5, 40) { editable = false } + contents += new ScrollPane(output) + + def outputSelection() { + output.append("Lead: " + table.selection.rows.leadIndex + "," + + table.selection.columns.leadIndex + ". ") + output.append("Rows:") + for (c <- table.selection.rows) output.append(" " + c) + output.append(". Columns:") + for (c <- table.selection.columns) output.append(" " + c) + output.append(".\n") + } + reactions += { + case ButtonClicked(_) => + rowSelection.selected = table.selection.elementMode == Table.ElementMode.Row + columnSelection.selected = table.selection.elementMode == Table.ElementMode.Column + if (cellSelection.enabled) { + cellSelection.selected = table.selection.elementMode == Table.ElementMode.Cell + } + } + + reactions += { + case ButtonClicked(`multiInterval`) => + table.selection.intervalMode = Table.IntervalMode.MultiInterval + if (cellSelection.selected) { + elemMutex.deselectAll() + table.selection.elementMode = Table.ElementMode.None + } + cellSelection.enabled = false + case ButtonClicked(`elementInterval`) => + table.selection.intervalMode = Table.IntervalMode.SingleInterval + cellSelection.enabled = true + case ButtonClicked(`singleInterval`) => + table.selection.intervalMode = Table.IntervalMode.Single + cellSelection.enabled = true + case ButtonClicked(`rowSelection`) => + if (rowSelection.selected) + table.selection.elementMode = Table.ElementMode.Row + case ButtonClicked(`columnSelection`) => + if (columnSelection.selected) + table.selection.elementMode = Table.ElementMode.Column + case ButtonClicked(`cellSelection`) => + if (cellSelection.selected) + table.selection.elementMode = Table.ElementMode.Cell + case RowsSelected(table, false, range) => + output.append("Rows selected, changes: " + range + "\n") + outputSelection() + case ColumnsSelected(table, false, range) => + output.append("Columns selected, changes " + range + "\n") + outputSelection() + } + } + } +} + |