Skip to content
Draft
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ project/plugins/project/

.idea/
.idea_modules/
/.bsp/
34 changes: 24 additions & 10 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,43 @@ name := "ScalaSwingContrib"

organization := "com.github.benhutchison"

version := "1.9"
version := "1.10-SNAPSHOT"

scalaVersion := "3.1.2"
scalaVersion := "3.3.3"

Global / onChangedBuildSource := ReloadOnSourceChanges

sonatypeProfileName := "com.github.benhutchison"

libraryDependencies ++= Seq(
"org.scala-lang.modules" %% "scala-swing" % "3.0.0",
"org.scala-lang.modules" %% "scala-xml" % "2.1.0",
"org.scala-lang.modules" %% "scala-xml" % "2.2.0",

"org.scala-lang.modules" %% "scala-collection-compat" % "2.7.0",
"org.scala-lang.modules" %% "scala-collection-compat" % "2.11.0",

"com.sun.activation" % "javax.activation" % "1.2.0", // clipboard data handlers - deprecated in SDK in Java 9, removed later

"org.specs2" %% "specs2-core" % "4.15.0" % Test,
"org.specs2" %% "specs2-junit" % "4.15.0" % Test,
"org.specs2" %% "specs2-core" % "4.20.4" % Test,
"org.specs2" %% "specs2-junit" % "4.20.5" % Test,

"junit" % "junit" % "4.7" % Test
"junit" % "junit" % "4.13.2" % Test
)

scalacOptions ++= Seq("-deprecation", "-unchecked", "-feature")

crossScalaVersions := Seq("2.12.15", "2.13.8", "3.1.2")
scalacOptions ++= {
if (scalaVersion.value.startsWith("2.13")) Seq("-Xsource:3")
else if (scalaVersion.value.startsWith("3.")) Seq(
"-Wconf:msg=Alphanumeric method .* is not declared infix:s",
"-Wconf:msg=is no longer supported for vararg splices:s",
"-Wconf:msg=`_` is deprecated for wildcard arguments of types:s",
"-Wconf:msg=Ignoring \\[this\\] qualifier:s",
"-Wconf:msg=with as a type operator has been deprecated:s",
//"-Wconf:msg=The syntax `<function> _` is no longer supported:s",
) else Seq()
}

crossScalaVersions := Seq("2.12.19", "2.13.13", "3.3.3", "3.4.1")

Compile / unmanagedSourceDirectories += {
val sourceDir = (Compile / sourceDirectory).value
Expand All @@ -37,7 +51,7 @@ Compile / unmanagedSourceDirectories += {
}
}

// Following settings taken from:
// Following settings taken from:
//https://github.com/sbt/sbt.github.com/blob/gen-master/src/jekyll/using_sonatype.md

publishMavenStyle := true
Expand Down Expand Up @@ -82,4 +96,4 @@ Global / pomExtra := (
<url>http://github.com:kenbot</url>
</developer>
</developers>)

2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=1.6.2
sbt.version=1.9.8
2 changes: 1 addition & 1 deletion src/main/scala-2.13+/scalaswingcontrib/MutableSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ package scalaswingcontrib
import scala.collection.mutable

trait MutableSet[A] extends mutable.Set[A] {
override def clear() = throw new NotImplementedError // required by 2.13, but we are not using it
override def clear(): Nothing = throw new NotImplementedError // required by 2.13, but we are not using it

}
30 changes: 15 additions & 15 deletions src/main/scala/scalaswingcontrib/AbsoluteLayoutPanel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,30 @@ import Swing._
Optionally, can be set to automatically adjust added child component location constraints to account
for the border/inset (if any). If adjustment is not performed, then child components can overlap the border
area.
*
* The preferredSize of the panel is auto-derived from the greatest bounds of child components, plus border if any.
*
* The preferredSize of the panel is auto-derived from the greatest bounds of child components, plus border if any.
* */
class AbsoluteLayoutPanel(val adjustForBorder: Boolean) extends Panel with Container.Wrapper with LayoutContainer {

def this() = this(false)
override lazy val peer = new javax.swing.JPanel(null) with SuperMixin

override lazy val peer: javax.swing.JPanel = new javax.swing.JPanel(null) with SuperMixin

type Constraints = (Int, Int)

protected def constraintsFor(comp: Component) = toTuple(comp.peer.getLocation)

protected def areValid(c: Constraints) = (true, "")

protected def add(comp: Component, c: Constraints): Unit = {
val xInset = if (adjustForBorder) insets.left else 0
val yInset = if (adjustForBorder) insets.top else 0
val xInset = if (adjustForBorder) insets.left else 0
val yInset = if (adjustForBorder) insets.top else 0

def adjusted(c: Constraints) = (c._1 + xInset, c._2 + yInset)

def largestChildSize: (Int, Int) = contents.foldLeft((0,0)) {(size, next) =>
import math.max
(max(size._1, next.location.x - xInset + next.size.width),
(max(size._1, next.location.x - xInset + next.size.width),
max(size._2, next.location.y - yInset + next.size.height))
}

Expand All @@ -41,10 +41,10 @@ class AbsoluteLayoutPanel(val adjustForBorder: Boolean) extends Panel with Conta
}
peer.add(comp.peer)
val (w, h) = largestChildSize

preferredSize = (w + insets.left + insets.right , h + insets.top + insets.bottom)
}

def insets = border.getBorderInsets(peer)

}
106 changes: 53 additions & 53 deletions src/main/scala/scalaswingcontrib/group/ComponentsInGroups.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import scala.swing.Component
import javax.{swing => js}
import scala.language.implicitConversions

/** Provides an implicit conversion and wrappers so that arbitrary Swing
/** Provides an implicit conversion and wrappers so that arbitrary Swing
* components may be placed inside a `GroupPanel` but still be checked for
* validity at compile time.
*
*
* @author Andreas Flierl
*/
trait ComponentsInGroups extends SizeTypes { this: GroupPanel =>
Expand All @@ -16,159 +16,159 @@ trait ComponentsInGroups extends SizeTypes { this: GroupPanel =>
*/
protected final implicit def add[A <: G](comp: Component): ComponentInGroup[A] =
new ComponentInGroup[A](comp)

/** Triplet of minimum, preferred and maximum size. */
private[group] case class Sizes(min: Size, pref: Size, max: Size)

/**
* Wraps an arbitrary component so that it may appear within a group of
* Wraps an arbitrary component so that it may appear within a group of
* type `A`.
*/
protected class ComponentInGroup[A <: G](comp: Component)
protected class ComponentInGroup[A <: G](comp: Component)
extends InGroup[A] with SizeHelpers[A] {

override private[group] def build(parent: A) = parent.addComponent(comp.peer)

/**
/**
* Specifies size constraints for this component.
*
*
* @param min minimum size >= 0 (or one of `UseDefault`, `UsePreferred` and `Infinite`)
* @param pref preferred size >= 0 (or one of `UseDefault`, `UsePreferred` and `Infinite`)
* @param max maximum size >= 0 (or one of `UseDefault`, `UsePreferred` and `Infinite`)
*/
def sized(min: Size, pref: Size, max: Size) =
def sized(min: Size, pref: Size, max: Size): InGroup[A] =
new ComponentWithSize[A](comp, Sizes(min, pref, max))

/** Specifies that this component should be used to calculate the baseline
* of its surrounding group, which must be sequential. This is needed to
* align that sequential group along the baseline of a baseline-aligned
* parallel group that surrounds it.
*
*
* Only *one* component in a sequential group should be marked this way.
* If there are several, the last one marked will be used.
*/
def asBaseline = new ComponentInSequential(comp, None, true)

/**
* Specifies an alignment for this component. May only be used inside a
* parallel group.
*
*
* @param newAlign the alignment to use
*/
def aligned(newAlign: Alignment) = new ComponentInParallel(comp, None, newAlign)
}

/**
* Wraps an arbitrary component to allow for custom size constraints.
*/
protected class ComponentWithSize[A <: G](comp: Component,
sizes: Sizes) extends InGroup[A] {
protected class ComponentWithSize[A <: G](comp: Component,
sizes: Sizes) extends InGroup[A] {
override private[group] def build(parent: A) =
parent.addComponent(comp.peer, sizes.min.pixels, sizes.pref.pixels,
parent.addComponent(comp.peer, sizes.min.pixels, sizes.pref.pixels,
sizes.max.pixels)

/** Specifies that this component should be used to calculate the baseline
* of its surrounding group, which must be sequential. This is needed to
* align that sequential group along the baseline of a baseline-aligned
* parallel group that surrounds it.
*
*
* Only *one* component in a sequential group should be marked this way.
* If there are several, the last one marked will be used.
*/
def asBaseline = new ComponentInSequential(comp, Some(sizes), true)
def asBaseline = new ComponentInSequential(comp, Some(sizes), true)

/**
* Specifies an alignment for this component. May only be used inside a
* parallel group.
*
*
* @param newAlign the alignment to use
*/
def aligned(newAlign: Alignment) =
new ComponentInParallel(comp, Some(sizes), newAlign)
}
}

/**
* Wraps a GUI component so that it may appear in a sequential group.
*
*
* @see javax.swing.GroupLayout.SequentialGroup
*/
protected class ComponentInSequential(comp: Component,
sizes: Option[Sizes], useAsBaseline: Boolean)
*/
protected class ComponentInSequential(comp: Component,
sizes: Option[Sizes], useAsBaseline: Boolean)
extends InSequential with SizeHelpers[js.GroupLayout#SequentialGroup] {

override private[group] def build(parent: js.GroupLayout#SequentialGroup) =
if (sizes.isDefined)
parent.addComponent(useAsBaseline, comp.peer, sizes.get.min.pixels,
if (sizes.isDefined)
parent.addComponent(useAsBaseline, comp.peer, sizes.get.min.pixels,
sizes.get.pref.pixels, sizes.get.max.pixels)
else parent.addComponent(useAsBaseline, comp.peer)
/**

/**
* Specifies size constraints for this component.
*
*
* @param min minimum size >= 0 (or one of `UseDefault`, `UsePreferred` and `Infinite`)
* @param pref preferred size >= 0 (or one of `UseDefault`, `UsePreferred` and `Infinite`)
* @param max maximum size >= 0 (or one of `UseDefault`, `UsePreferred` and `Infinite`)
*/
def sized(min: Size, pref: Size, max: Size) =
def sized(min: Size, pref: Size, max: Size): InSequential =
new ComponentInSequential(comp, Some(Sizes(min, pref, max)), useAsBaseline)
}

/**
* Wraps a GUI component so that it may appear in a parallel group.
*
*
* @see javax.swing.GroupLayout.ParallelGroup
*/
*/
protected class ComponentInParallel(comp: Component,
sizes: Option[Sizes], align: Alignment)
sizes: Option[Sizes], align: Alignment)
extends InParallel with SizeHelpers[js.GroupLayout#ParallelGroup] {

override private[group] def build(parent: js.GroupLayout#ParallelGroup) =
if (sizes.isDefined)
parent.addComponent(comp.peer, align.wrapped, sizes.get.min.pixels,
parent.addComponent(comp.peer, align.wrapped, sizes.get.min.pixels,
sizes.get.pref.pixels, sizes.get.max.pixels)
else parent.addComponent(comp.peer, align.wrapped)

/**
/**
* Specifies size constraints for this component.
*
*
* @param min minimum size >= 0 (or one of `UseDefault`, `UsePreferred` and `Infinite`)
* @param pref preferred size >= 0 (or one of `UseDefault`, `UsePreferred` and `Infinite`)
* @param max maximum size >= 0 (or one of `UseDefault`, `UsePreferred` and `Infinite`)
*/
def sized(min: Size, pref: Size, max: Size) =
def sized(min: Size, pref: Size, max: Size): InParallel =
new ComponentInParallel(comp, Some(Sizes(min, pref, max)), align)
}

/**
* Additional methods for nicer control over resizing behaviour.
* Additional methods for nicer control over resizing behaviour.
*/
private[group] trait SizeHelpers[A <: G] {
/**
/**
* Specifies size constraints for this component.
*
*
* @param min minimum size >= 0 (or one of `UseDefault`, `UsePreferred` and `Infinite`)
* @param pref preferred size >= 0 (or one of `UseDefault`, `UsePreferred` and `Infinite`)
* @param max maximum size >= 0 (or one of `UseDefault`, `UsePreferred` and `Infinite`)
*/
def sized(min: Size, pref: Size, max: Size): InGroup[A]

/**
* Fixes the size of this component to its default size.
*/
def fixedToDefaultSize = sized(UsePreferred, UseDefault, UsePreferred)

/**
* Fixes the size of this component to the specified size.
*
* @param size the desired size in pixels
*
* @param size the desired size in pixels
*/
def sized(size: Size): InGroup[A] = sized(UsePreferred, size, UsePreferred)

/**
* Forces this component to be resizable (useful e.g. for buttons). Its
* minimum size is set to its default size.
*/
def resizable(min: Size = UseDefault, pref: Size = UseDefault, max: Size = Infinite) =
def resizable(min: Size = UseDefault, pref: Size = UseDefault, max: Size = Infinite) =
sized(min, pref, max)

/**
Expand Down
Loading