diff --git a/src/main/scala/scala/swing/DesktopPane.scala b/src/main/scala/scala/swing/DesktopPane.scala new file mode 100644 index 00000000..b63fe43c --- /dev/null +++ b/src/main/scala/scala/swing/DesktopPane.scala @@ -0,0 +1,71 @@ +package scala.swing + +import javax.swing.JDesktopPane + +import scala.collection.immutable + + +/** + * A pane that can host nested internal windows (represented by [[InternalFrame]]). + */ +class DesktopPane extends Component with SequentialContainer.Wrapper { + import DesktopPane._ + + override lazy val peer : JDesktopPane = new JDesktopPane with SuperMixin + + /** + * Returns all internal frames in this pane, including iconified ones. + * + * @return a list of internal frames. + */ + def frames : immutable.Seq[InternalFrame] = + peer.getAllFrames.toSeq.view.map(UIElement.cachedWrapper[InternalFrame]).toVector + + /** + * Returns the currently selected frame, if one is selected. + * + * @return the currently selected frame, or `None` if none is selected. + */ + def selectedFrame : Option[InternalFrame] = + Option(peer.getSelectedFrame).map(UIElement.cachedWrapper[InternalFrame]) + + /** + * Indicates how dragged frames will be animated. + * + * @return either `LiveDragMode` or `OutlineDragMode`. + */ + def dragMode : DragMode = DragMode(peer.getDragMode) + + /** + * Specifies how dragged frames will be animated. + * + * @param newMode either `DragMode.Live` or `DragMode.Outline`. + */ + def dragMode_= (newMode : DragMode) : Unit = peer.setDragMode(newMode.id) +} + + +object DesktopPane { + + /** + * Supported drag modes for internal frames. + */ + //noinspection TypeAnnotation + object DragMode extends Enumeration { + /** + * Renders the contents of the frame while dragging. + */ + val Live = Value(JDesktopPane.LIVE_DRAG_MODE) + + /** + * Renders only the outline of the frame while dragging. + */ + val Outline = Value(JDesktopPane.OUTLINE_DRAG_MODE) + } + + /** + * Type indicating how an internal frame will be animated as it is dragged. + */ + type DragMode = DragMode.Value + +} diff --git a/src/main/scala/scala/swing/InternalFrame.scala b/src/main/scala/scala/swing/InternalFrame.scala new file mode 100644 index 00000000..d8d0eb36 --- /dev/null +++ b/src/main/scala/scala/swing/InternalFrame.scala @@ -0,0 +1,114 @@ +package scala.swing + +import javax.swing.{Icon, JInternalFrame, WindowConstants} + +import scala.swing.MenuBar.NoMenuBar +import scala.swing.event.{InternalFrameActivated, InternalFrameClosed, InternalFrameClosing, InternalFrameDeactivated, InternalFrameDeiconified, InternalFrameIconified, InternalFrameOpened} + + +/** + * A window that can be nested inside another window (typically within a [[DesktopPane]]). + */ +class InternalFrame extends Component with RootPanel with Publisher { outer => + import javax.swing.event.{InternalFrameEvent => PeerEvent, InternalFrameListener => PeerListener} + + override lazy val peer: JInternalFrame = new JInternalFrame with InterfaceMixin + peer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE) + + trait InterfaceMixin extends JInternalFrame with SuperMixin { + override def doDefaultCloseAction(): Unit = { + super.doDefaultCloseAction() + closeOperation() + } + } + + def title: String = peer.getTitle + def title_=(s: String): Unit = peer.setTitle(s) + + /** + * The menu bar of this frame or [[NoMenuBar]] if no menu bar is set. + */ + def menuBar: MenuBar = { + val m = UIElement.cachedWrapper[MenuBar](peer.getJMenuBar) + if (m != null) m else MenuBar.NoMenuBar + } + + /** + * Set the current menu bar of this frame. Pass `NoMenuBar` if this frame + * should not show a menu bar. + */ + def menuBar_=(m: MenuBar): Unit = + peer.setJMenuBar(if (m == MenuBar.NoMenuBar) null else m.peer) + + def resizable_=(b: Boolean): Unit = peer.setResizable(b) + def resizable: Boolean = peer.isResizable + + def maximizable : Boolean = peer.isMaximizable + def maximizable_= (b : Boolean) : Unit = peer.setMaximizable(b) + + def maximized : Boolean = peer.isMaximum + def maximize() : Unit = peer.setMaximum(true) + def unmaximize() : Unit = peer.setMaximum(false) + + def location_=(p: Point): Unit = peer.setLocation(p) + def size_=(size: Dimension): Unit = peer.setSize(size) + def bounds_=(rect: Rectangle): Unit = peer.setBounds(rect) + + def closable : Boolean = peer.isClosable + def closable_= (b : Boolean): Unit = peer.setClosable(b) + + def closed : Boolean = peer.isClosed + def close() : Unit = peer.setClosed(true) + + def iconifiable : Boolean = peer.isIconifiable + def iconifiable_= (b : Boolean) : Unit = peer.setIconifiable(b) + + def iconified : Boolean = peer.isIcon + def iconify() : Unit = peer.setIcon(true) + def uniconify() : Unit = peer.setIcon(false) + + def frameIcon : Icon = peer.getFrameIcon + def frameIcon_= (icon : Icon) : Unit = peer.setFrameIcon(icon) + + def dispose(): Unit = peer.dispose() + + def pack(): this.type = { peer.pack(); this } + + def show() : Unit = peer.show() + def hide() : Unit = peer.hide() + + def moveToBack() : Unit = peer.moveToBack() + def moveToFront() : Unit = peer.moveToFront() + + def layer : Int = peer.getLayer + def layer_= (n : Int) : Unit = peer.setLayer(n) + + def selected : Boolean = peer.isSelected + def select() : Unit = peer.setSelected(true) + def deselect() : Unit = peer.setSelected(false) + + /** + * This method is called when the window is closing, after all other window + * event listeners have been processed. + * + * Default behavior is to dispose of the internal frame, but other options include hiding the frame + * or doing nothing at all. + */ + def closeOperation(): Unit = dispose() + + peer.addInternalFrameListener(new PeerListener { + override def internalFrameOpened(e: PeerEvent): Unit = publish(InternalFrameOpened(outer)) + + override def internalFrameClosing(e: PeerEvent): Unit = publish(InternalFrameClosing(outer)) + + override def internalFrameClosed(e: PeerEvent): Unit = publish(InternalFrameClosed(outer)) + + override def internalFrameIconified(e: PeerEvent): Unit = publish(InternalFrameIconified(outer)) + + override def internalFrameDeiconified(e: PeerEvent): Unit = publish(InternalFrameDeiconified(outer)) + + override def internalFrameActivated(e: PeerEvent): Unit = publish(InternalFrameActivated(outer)) + + override def internalFrameDeactivated(e: PeerEvent): Unit = publish(InternalFrameDeactivated(outer)) + }) +} diff --git a/src/main/scala/scala/swing/event/InternalFrameEvent.scala b/src/main/scala/scala/swing/event/InternalFrameEvent.scala new file mode 100644 index 00000000..100269ee --- /dev/null +++ b/src/main/scala/scala/swing/event/InternalFrameEvent.scala @@ -0,0 +1,26 @@ +package scala.swing.event + +import scala.swing.InternalFrame + + +/** + * Base class for events generated by instances of [[InternalFrame]]. + * + * @param source the `InternalFrame` that generated the event. + */ +abstract class InternalFrameEvent(override val source : InternalFrame) extends UIEvent + +case class InternalFrameOpened(override val source : InternalFrame) extends InternalFrameEvent(source) + +case class InternalFrameClosing(override val source : InternalFrame) extends InternalFrameEvent(source) + +case class InternalFrameClosed(override val source : InternalFrame) extends InternalFrameEvent(source) + +case class InternalFrameIconified(override val source : InternalFrame) extends InternalFrameEvent(source) + +case class InternalFrameDeiconified(override val source : InternalFrame) extends InternalFrameEvent(source) + +case class InternalFrameActivated(override val source : InternalFrame) extends InternalFrameEvent(source) + +case class InternalFrameDeactivated(override val source : InternalFrame) extends InternalFrameEvent(source) +