![JAR search and dependency download from the Maven repository](/logo.png)
moreswing.swing.GridBoundaries.scala Maven / Gradle / Ivy
The newest version!
package moreswing.swing
import scala.swing. { Dimension, Rectangle }
/** Hold rectangles in a grid.
*
* @author myst3r10n
*/
trait GridBoundaries {
/** Minimum bounds size. */
var minimumBoundsSize = new Dimension(25, 25)
/** Throw this exception if minimum bounds width exceeded. */
protected case class MinimumBoundsWidthExceeded(o: Int) extends Exception {
/** Amount size exceeded. */
val offset = o
}
/** Throw this exception if minimum bounds width is invalid. */
case object MinimumBoundsWidthInvalid extends Exception
/** Throw this exception if minimum bounds height exceeded. */
case class MinimumBoundsHeightExceeded(o: Int) extends Exception {
/** Amount size exceeded. */
val offset = o
}
/** Throw this exception if minimum bounds height is invalid. */
case object MinimumBoundsHeightInvalid extends Exception { }
/** Fit all overlapped bounds and removes empty fields.
*
* @param start The index of the bounds where changed first.
* @param newBounds The new bounds of the rectangle where changed first.
* @param boundaries The boundaries without the new changed start bounds.
*
* @return The modified rectangles.
*/
def fitBoundaries(
start: Int,
newBounds: Rectangle,
boundaries: Map[Int, Rectangle]): Map[Int, Rectangle] = {
// Pass if minimum bounds sizes empty.
if(minimumBoundsSizes == null) {
// Pass if minimum bounds width invalid.
if(minimumBoundsSize.width < 0)
throw MinimumBoundsWidthInvalid
// Pass if minimum bounds height invalid.
else if(minimumBoundsSize.height < 0)
throw MinimumBoundsHeightInvalid
// Pass if minimum bounds sizes not empty.
} else
// Check whether minimum sizes valid.
minimumBoundsSizes.foreach { case (i, size) =>
// Pass if minimum bounds width invalid.
if(size.width < 0)
throw MinimumBoundsWidthInvalid
// Pass if minimum bounds height invalid.
else if(size.height < 0)
throw MinimumBoundsHeightInvalid
}
// Sync boundaries.
formerBoundaries = boundaries
newestBoundaries = boundaries
newestBoundaries += start -> newBounds
// Add start bounds to change.
var changeBoundaries = Seq[Int](start)
// Mark start bounds as modified.
var modifiedBoundaries = Map[Int, Rectangle]((changeBoundaries.head, newBounds))
// Adjustment algorithm.
while(changeBoundaries.size > 0) try {
while(changeBoundaries.size > 0) {
// Pass if left boundary moved.
if(formerBoundaries(changeBoundaries.head).x !=
newestBoundaries(changeBoundaries.head).x) {
// Update all left neighbor boundaries.
neighbors(changeBoundaries.head, Direction.Left).foreach { neighbor =>
// New bounds of left neighbor bounds.
val newNeighborBounds = new Rectangle(
newestBoundaries(neighbor).x,
newestBoundaries(neighbor).y,
newestBoundaries(changeBoundaries.head).x -
newestBoundaries(neighbor).x,
newestBoundaries(neighbor).height)
// Mark left neighbor bounds as modified.
modifiedBoundaries += neighbor -> newNeighborBounds
// Update boundaries with left neighbor bounds.
newestBoundaries += neighbor -> newNeighborBounds
// Remember to resize all boundaries around the left neighbor bounds too.
changeBoundaries = changeBoundaries :+ neighbor
}
// Pass if right boundary moved.
} else if(formerBoundaries(changeBoundaries.head).width !=
newestBoundaries(changeBoundaries.head).width) {
// Update right neighbor boundaries.
neighbors(changeBoundaries.head, Direction.Right).foreach { neighbor =>
// New bounds of right neighbor bounds.
val newNeighborBounds = new Rectangle(
newestBoundaries(changeBoundaries.head).x +
newestBoundaries(changeBoundaries.head).width,
newestBoundaries(neighbor).y,
newestBoundaries(neighbor).width -
((newestBoundaries(changeBoundaries.head).x +
newestBoundaries(changeBoundaries.head).width) -
newestBoundaries(neighbor).x),
newestBoundaries(neighbor).height)
// Mark right neighbor bounds as modified.
modifiedBoundaries += neighbor -> newNeighborBounds
// Update boundaries with right neighbor bounds.
newestBoundaries += neighbor -> newNeighborBounds
// Remember to resize all boundaries around the right neighbor bounds too.
changeBoundaries = changeBoundaries :+ neighbor
}
}
// Pass if top boundary moved.
if(formerBoundaries(changeBoundaries.head).y !=
newestBoundaries(changeBoundaries.head).y) {
// Update top neighbor boundaries.
neighbors(changeBoundaries.head, Direction.Top).foreach { neighbor =>
// New bounds of top neighbor bounds.
val newNeighborBounds = new Rectangle(
newestBoundaries(neighbor).x,
newestBoundaries(neighbor).y,
newestBoundaries(neighbor).width,
newestBoundaries(changeBoundaries.head).y -
newestBoundaries(neighbor).y)
// Mark top neighbor bounds as modified.
modifiedBoundaries += neighbor -> newNeighborBounds
// Update boundaries with top neighbor bounds.
newestBoundaries += neighbor -> newNeighborBounds
// Remember to resize all boundaries around the top neighbor bounds too.
changeBoundaries = changeBoundaries :+ neighbor
}
// Pass if bottom boundary moved.
} else if(formerBoundaries(changeBoundaries.head).height !=
newestBoundaries(changeBoundaries.head).height) {
// Update bottom neighbor boundaries.
neighbors(changeBoundaries.head, Direction.Bottom).foreach { neighbor =>
// New bounds of bottom neighbor bounds.
val newNeighborBounds = new Rectangle(
newestBoundaries(neighbor).x,
newestBoundaries(changeBoundaries.head).y +
newestBoundaries(changeBoundaries.head).height,
newestBoundaries(neighbor).width,
newestBoundaries(neighbor).height -
((newestBoundaries(changeBoundaries.head).y +
newestBoundaries(changeBoundaries.head).height) -
newestBoundaries(neighbor).y))
// Mark bottom neighbor bounds as modified.
modifiedBoundaries += neighbor -> newNeighborBounds
// Update boundaries with bottom neighbor bounds.
newestBoundaries += neighbor -> newNeighborBounds
// Remember to resize all boundaries around the bottom neighbor bounds too.
changeBoundaries = changeBoundaries :+ neighbor
}
}
// Sync former bounds with changed bounds.
formerBoundaries += changeBoundaries.head -> newestBoundaries(changeBoundaries.head)
// Mark bounds as changed.
changeBoundaries = changeBoundaries.drop(1)
}
} catch {
case e: MinimumBoundsWidthExceeded =>
// Reset changes and add start bounds to change.
changeBoundaries = Seq[Int](start)
// Reset former boundaries and sync boundaries again.
formerBoundaries = boundaries
// Init patch bounds.
val patch = new Rectangle(
newestBoundaries(changeBoundaries.head).x,
newestBoundaries(changeBoundaries.head).y,
newestBoundaries(changeBoundaries.head).width,
newestBoundaries(changeBoundaries.head).height)
// Patch left boundary of start bounds.
if(formerBoundaries(changeBoundaries.head).x >
newestBoundaries(changeBoundaries.head).x) {
patch.x += e.offset
patch.width -= e.offset
// Patch left boundary of start bounds.
} else if(formerBoundaries(changeBoundaries.head).x <
newestBoundaries(changeBoundaries.head).x) {
patch.x -= e.offset
patch.width += e.offset
// Patch right boundary of start bounds.
} else if (formerBoundaries(changeBoundaries.head).width >
newestBoundaries(changeBoundaries.head).width)
patch.width += e.offset
// Patch right boundary of start bounds.
else if(formerBoundaries(changeBoundaries.head).width <
newestBoundaries(changeBoundaries.head).width)
patch.width -= e.offset
// Reset modified boundaries and mark start bounds as modified.
modifiedBoundaries = Map[Int, scala.swing.Rectangle]((changeBoundaries.head, patch))
// Reset newest boundaries and sync boundaries again.
newestBoundaries = boundaries
newestBoundaries += changeBoundaries.head -> modifiedBoundaries(changeBoundaries.head)
case e: MinimumBoundsHeightExceeded =>
// Reset changes and add start bounds to change.
changeBoundaries = Seq[Int](start)
// Reset fromer boundaries and sync boundaries again.
formerBoundaries = boundaries
// Init patch bounds.
val patch = new Rectangle(
newestBoundaries(changeBoundaries.head).x,
newestBoundaries(changeBoundaries.head).y,
newestBoundaries(changeBoundaries.head).width,
newestBoundaries(changeBoundaries.head).height)
// Patch top boundary of start bounds.
if(formerBoundaries(changeBoundaries.head).y >
newestBoundaries(changeBoundaries.head).y) {
patch.y += e.offset
patch.height -= e.offset
// Patch top boundary of start bounds.
} else if(formerBoundaries(changeBoundaries.head).y <
newestBoundaries(changeBoundaries.head).y) {
patch.y -= e.offset
patch.height += e.offset
// Patch bottom boundary of start bounds.
} else if (formerBoundaries(changeBoundaries.head).height >
newestBoundaries(changeBoundaries.head).height)
patch.height += e.offset
// Patch bottom boundary of start bounds.
else if(formerBoundaries(changeBoundaries.head).height <
newestBoundaries(changeBoundaries.head).height)
patch.height -= e.offset
// Reset modified boundaries and mark start bounds as modified.
modifiedBoundaries =
Map[Int, scala.swing.Rectangle]((changeBoundaries.head, patch))
// Reset newest boundaries and sync boundaries again.
newestBoundaries = boundaries
newestBoundaries +=
changeBoundaries.head -> modifiedBoundaries(changeBoundaries.head)
}
// Removes all minimum boundaries sizes.
if(minimumBoundsSizes != null)
minimumBoundsSizes = null
// Modified boundaries.
modifiedBoundaries
}
/** Fit all overlapped rectangles and removes empty fields.
*
* @param start The index of the rectangle where changed first.
* @param newBounds The new bounds of the rectangle where changed first.
* @param rectangles The bounds of rectangles without the new bounds of the first changed.
* @param minimumBoundsSizes The minimum sizes of boundaries.
*
* @return The modified rectangles.
*/
def fitBoundaries(
start: Int,
newBounds: Rectangle,
boundaries: Map[Int, Rectangle],
minimumBoundsSizes: Map[Int, Dimension]): Map[Int, Rectangle] = {
this.minimumBoundsSizes = minimumBoundsSizes
fitBoundaries(start, newBounds, boundaries)
}
/** Direction of the neighbors. */
protected object Direction extends Enumeration {
/** Is left neighbor. */
val Left = Value("Left")
/** Is right neighbor. */
val Right = Value("Right")
/** Is top neighbor. */
val Top = Value("Top")
/** Is bottom neighbor. */
val Bottom = Value("Bottom")
}
/** Neighboring boundaries of a central bounds.
*
* @param central The central bounds.
* @param direction The direction of its neighbors.
*/
protected def neighbors(central: Int, direction: Direction.Value): Seq[Int] = {
// found neighbor boundaries.
var found = Seq[Int]()
// Central bounds.
val centralBounds = newestBoundaries(central)
// Central bounds previously.
val centralBoundsAgo = formerBoundaries(central)
// Central minimum size.
val centralMinimumSize = if(minimumBoundsSizes == null) minimumBoundsSize else minimumBoundsSizes(central)
// Find all neighbors bounds.
newestBoundaries.foreach { case (neighbor, neighborBounds) =>
// Direction filter
direction match {
// Find left bounds.
case Direction.Left =>
// Search criterion for a left neighbor bounds.
if(!(neighborBounds.y + neighborBounds.height <= centralBounds.y) &&
neighborBounds.x + neighborBounds.width == centralBoundsAgo.x &&
!(centralBounds.y + centralBounds.height <= neighborBounds.y)) {
// If minimum width of left neighbor bounds exceeded, throw exception.
if(centralBounds.x - neighborBounds.x < centralMinimumSize.width)
throw MinimumBoundsWidthExceeded((centralMinimumSize.width -
(centralBounds.x - neighborBounds.x)))
// Add found left neighbor bounds.
found = found :+ neighbor
}
// Find right bounds.
case Direction.Right =>
// Search criterion for a right neighbor bounds.
if(!(neighborBounds.y + neighborBounds.height <= centralBounds.y) &&
centralBoundsAgo.x + centralBoundsAgo.width == neighborBounds.x &&
!(centralBounds.y + centralBounds.height <= neighborBounds.y)) {
// If minimum width of right neighbor bounds exceeded, throw exception.
if(neighborBounds.width - ((centralBounds.x + centralBounds.width) -
neighborBounds.x) < centralMinimumSize.width)
throw MinimumBoundsWidthExceeded((centralMinimumSize.width -
(neighborBounds.width -
((centralBounds.x + centralBounds.width) - neighborBounds.x))))
// Add found right neighbor bounds.
found = found :+ neighbor
}
// Find top bounds.
case Direction.Top =>
// Search criterion for a top neighbor bounds.
if(neighborBounds.y + neighborBounds.height == centralBoundsAgo.y &&
!(neighborBounds.x + neighborBounds.width <= centralBounds.x) &&
!(centralBounds.x + centralBounds.width <= neighborBounds.x)) {
// If minimum height of top neighbor bounds exceeded, throw exception.
if(centralBounds.y - neighborBounds.y < centralMinimumSize.height)
throw MinimumBoundsHeightExceeded(centralMinimumSize.height - (centralBounds.y - neighborBounds.y))
// Add found top neighbor bounds.
found = found :+ neighbor
}
// Find bottom bounds.
case Direction.Bottom =>
// Search criteria for a bottom neighbor bounds.
if(!(neighborBounds.x + neighborBounds.width <= centralBounds.x) &&
!(centralBounds.x + centralBounds.width <= neighborBounds.x) &&
centralBoundsAgo.y + centralBoundsAgo.height == neighborBounds.y) {
// If minimum height of bottom neighbor bounds exceeded, throw exception.
if(neighborBounds.height -
((centralBounds.y + centralBounds.height) - neighborBounds.y) < centralMinimumSize.height)
throw MinimumBoundsHeightExceeded((centralMinimumSize.height -
(neighborBounds.height - ((centralBounds.y + centralBounds.height) - neighborBounds.y))))
// Add found bottom neighbor bounds.
found = found :+ neighbor
}
}
}
found
}
/** Former boundaries. */
private var formerBoundaries: Map[Int, Rectangle] = null
/** Newest boundaries. */
private var newestBoundaries: Map[Int, Rectangle] = null
/** Minimum bounds sizes. */
private var minimumBoundsSizes: Map[Int, Dimension] = null
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy