diff --git a/src/main/scala/hevs/graphics/FunGraphics.scala b/src/main/scala/hevs/graphics/FunGraphics.scala
index b7b1bcc..3b228dc 100644
--- a/src/main/scala/hevs/graphics/FunGraphics.scala
+++ b/src/main/scala/hevs/graphics/FunGraphics.scala
@@ -8,9 +8,10 @@ import hevs.graphics.utils.RepeatingReleasedEventsFixer
import javax.imageio.ImageIO
import java.awt._
import java.awt.event._
-import java.awt.font.TextLayout
-import java.awt.geom.AffineTransform
+import java.awt.font.{LineMetrics, TextLayout}
+import java.awt.geom.{AffineTransform, Rectangle2D}
import java.io._
+import javax.swing.SwingConstants
/**
* Factory for [[hevs.graphics.FunGraphics]].
@@ -282,14 +283,19 @@ class FunGraphics(val width: Int, val height: Int, val xoffset: Int, val yoffset
g2d.fillOval(posX, posY, width, height)
}
- override def drawString(posX: Int, posY: Int, str: String): Unit = {
- g2d.drawString(str, posX, posY)
+ override def getStringSize(str: String, font: Font): Rectangle2D = {
+ val metrics: LineMetrics = font.getLineMetrics(str, g2d.getFontRenderContext)
+ val rect: Rectangle2D = font.getStringBounds(str, g2d.getFontRenderContext)
+ val height: Double = rect.getHeight - metrics.getDescent - metrics.getLeading
+ new Rectangle(rect.getWidth.toInt, height.toInt)
}
- override def drawString(posX: Int, posY: Int, str: String, color: Color, size: Int): Unit = {
+ override def getStringSize(str: String): Rectangle2D = getStringSize(str, g2d.getFont)
+
+ override def drawString(posX: Int, posY: Int, str: String, font: Font, color: Color): Unit = {
val oldFont = g2d.getFont
val oldColor = g2d.getColor
- val font = new Font("SansSerif", Font.PLAIN, size)
+
g2d.setFont(font)
g2d.setColor(color)
g2d.drawString(str, posX, posY)
@@ -297,18 +303,118 @@ class FunGraphics(val width: Int, val height: Int, val xoffset: Int, val yoffset
g2d.setColor(oldColor)
}
+ override def drawString(posX: Int,
+ posY: Int,
+ str: String,
+ font: Font,
+ color: Color,
+ halign: Int,
+ valign: Int): Unit = {
+
+ val bounds: Rectangle2D = getStringSize(str, font)
+ val w: Double = bounds.getWidth
+ val h: Double = bounds.getHeight
+
+ var x: Double = posX
+ var y: Double = posY
+
+ if (halign == SwingConstants.CENTER) {
+ x -= w / 2.0
+ } else if (halign == SwingConstants.RIGHT) {
+ x -= w
+ }
+
+ if (valign == SwingConstants.CENTER) {
+ y += h / 2.0
+ } else if (valign == SwingConstants.TOP) {
+ y += h
+ }
+
+ drawString(math.round(x).toInt, math.round(y).toInt, str, font, color)
+ }
+
+ override def drawString(posX: Int,
+ posY: Int,
+ str: String,
+ fontFamily: String = "SansSerif",
+ fontStyle: Int = Font.PLAIN,
+ fontSize: Int = 20,
+ color: Color = Color.BLACK,
+ halign: Int = SwingConstants.LEFT,
+ valign: Int = SwingConstants.BOTTOM): Unit = {
+
+ val font = new Font(fontFamily, fontStyle, fontSize)
+ drawString(posX, posY, str, font, color, halign, valign)
+ }
+
+ override def drawString(posX: Int, posY: Int, str: String, color: Color, size: Int): Unit = {
+ drawString(posX, posY, str, fontSize = size, color = color)
+ }
+
override def drawFancyString(posX: Int, posY: Int, str: String, color: Color, size: Int): Unit = {
- val g2 = g2d
- val oldFont = g2d.getFont
- val oldColor = g2d.getColor
- val font = new Font("Georgia", Font.BOLD, size)
- val textLayout = new TextLayout(str, font, g2.getFontRenderContext)
- g2.setColor(Color.GRAY)
- textLayout.draw(g2, (posX + 2).toFloat, (posY + 2).toFloat)
- g2.setColor(color)
- textLayout.draw(g2, posX.toFloat, posY.toFloat)
- g2.setFont(oldFont)
- g2.setColor(oldColor)
+ val font: Font = new Font("Georgia", Font.BOLD, size)
+ drawString(posX+2, posY+2, str, font, color = Color.GRAY)
+ drawString(posX, posY, str, fontSize = size, color = color)
+ }
+
+ override def drawFancyString(posX: Int,
+ posY: Int,
+ str: String,
+ fontFamily: String = "Georgia",
+ fontStyle: Int = Font.BOLD,
+ fontSize: Int = 20,
+ color: Color = Color.BLACK,
+ halign: Int = SwingConstants.LEFT,
+ valign: Int = SwingConstants.BOTTOM,
+ shadowX: Int = 0,
+ shadowY: Int = 0,
+ shadowColor: Color = Color.GRAY,
+ shadowThickness: Int = 0,
+ outlineColor: Color = Color.WHITE,
+ outlineThickness: Int = 0): Unit = {
+
+ val font: Font = new Font(fontFamily, fontStyle, fontSize)
+
+ if (shadowThickness > 0) {
+ val bounds: Rectangle2D = getStringSize(str, font)
+ val w: Double = bounds.getWidth
+ val h: Double = bounds.getHeight
+
+ var cx: Double = posX
+ var cy: Double = posY
+
+ if (halign == SwingConstants.LEFT) {
+ cx += w / 2.0
+ } else if (halign == SwingConstants.RIGHT) {
+ cx -= w / 2.0
+ }
+
+ if (valign == SwingConstants.TOP) {
+ cy += h / 2.0
+ } else if (valign == SwingConstants.BOTTOM) {
+ cy -= h / 2.0
+ }
+
+ val font2: Font = new Font(fontFamily, fontStyle, fontSize+shadowThickness)
+ drawString(
+ math.round(cx + shadowX).toInt,
+ math.round(cy + shadowY).toInt,
+ str,
+ font2,
+ shadowColor,
+ SwingConstants.CENTER,
+ SwingConstants.CENTER)
+ }
+
+ if (outlineThickness > 0) {
+ for (dy: Int <- -outlineThickness to outlineThickness) {
+ for (dx: Int <- -outlineThickness to outlineThickness) {
+ drawString(posX + dx, posY + dy, str, font, outlineColor, halign, valign)
+ }
+ }
+ }
+
+ drawString(posX, posY, str, font, color, halign, valign)
}
override def drawPicture(posX: Int, posY: Int, bitmap: GraphicsBitmap): Unit = {
@@ -347,6 +453,8 @@ class FunGraphics(val width: Int, val height: Int, val xoffset: Int, val yoffset
override def getFrameWidth(): Int = fWidth
override def getFrameHeight(): Int = fHeight
+ override def getAvailableFonts(): Array[String] = GraphicsEnvironment.getLocalGraphicsEnvironment.getAvailableFontFamilyNames
+
/**
* A sample game loop using explicit synchronization (if display flickers)
*/
diff --git a/src/main/scala/hevs/graphics/interfaces/Graphics.scala b/src/main/scala/hevs/graphics/interfaces/Graphics.scala
index 2fbb719..70ab847 100644
--- a/src/main/scala/hevs/graphics/interfaces/Graphics.scala
+++ b/src/main/scala/hevs/graphics/interfaces/Graphics.scala
@@ -2,9 +2,9 @@ package hevs.graphics.interfaces
import hevs.graphics.FunGraphics
import hevs.graphics.utils.GraphicsBitmap
-import java.awt.Color
-import java.awt.Polygon
-import java.awt.Rectangle
+
+import java.awt.geom.Rectangle2D
+import java.awt.{Color, Font, Polygon, Rectangle}
/**
@@ -181,6 +181,71 @@ trait Graphics {
*/
def drawFilledOval(posX: Int, posY: Int, width: Int, height: Int): Unit
+ /**
+ * Computes the size necessary to render a string with the given font
+ * @param str
+ * the string
+ * @param font
+ * the font
+ * @return the bounding box of the rendered string
+ */
+ def getStringSize(str: String, font: Font): Rectangle2D
+
+
+ /**
+ * Computes the size necessary to render a string with the current font
+ * @param str
+ * the string
+ * @return the bounding box of the rendered string
+ */
+ def getStringSize(str: String): Rectangle2D
+
+ /**
+ * Draws a string at a given location with the given font and color. Note that the boundaries are not
+ * checked and text may be painted outside the window
+ * @param posX
+ * X position of string
+ * @param posY
+ * Y position of string
+ * @param str
+ * the string to write
+ * @param font
+ * the font
+ * @param color
+ * the text color
+ */
+ def drawString(posX: Int,
+ posY: Int,
+ str: String,
+ font: Font,
+ color: Color): Unit
+
+ /**
+ * Draws a string at a given location with the given font, color and alignments. Note that the boundaries are not
+ * checked and text may be painted outside the window
+ * @param posX
+ * X position of string
+ * @param posY
+ * Y position of string
+ * @param str
+ * the string to write
+ * @param font
+ * the font
+ * @param color
+ * the text color
+ * @param halign
+ * the horizontal alignment (see {@link javax.swing.SwingConstants})
+ * @param valign
+ * the vertical alignment (see {@link javax.swing.SwingConstants})
+ */
+ def drawString(posX: Int,
+ posY: Int,
+ str: String,
+ font: Font,
+ color: Color,
+ halign: Int,
+ valign: Int): Unit
+
/**
* Draws a string at a given location. Note that the boundaries are not
* checked and text may be painted outside the window
@@ -191,8 +256,28 @@ trait Graphics {
* Y position of string
* @param str
* the string to write
+ * @param fontFamily
+ * the font family
+ * @param fontStyle
+ * the font style (plain, bold, italics, ...)
+ * @param fontSize
+ * the font size
+ * @param color
+ * the text color
+ * @param halign
+ * the horizontal alignment (see {@link javax.swing.SwingConstants})
+ * @param valign
+ * the vertical alignment (see {@link javax.swing.SwingConstants})
*/
- def drawString(posX: Int, posY: Int, str: String): Unit
+ def drawString(posX: Int,
+ posY: Int,
+ str: String,
+ fontFamily: String,
+ fontStyle: Int,
+ fontSize: Int,
+ color: Color,
+ halign: Int,
+ valign: Int): Unit
/**
* Write the given string at posX, posY
@@ -221,6 +306,41 @@ trait Graphics {
*/
def drawFancyString(posX: Int, posY: Int, str: String, color: Color, size: Int): Unit
+ /**
+ * Draws a text with a shadow or outline
+ * @param posX
+ * X position of the string
+ * @param posY
+ * Y position of the string
+ * @param str
+ * the string to draw
+ * @param fontFamily
+ * the font family
+ * @param fontStyle
+ * the font style (plain, bold, italics, ...)
+ * @param fontSize
+ * the font size
+ * @param color
+ * the text color
+ * @param halign
+ * the horizontal alignment (see {@link javax.swing.SwingConstants})
+ * @param valign
+ * the vertical alignment (see {@link javax.swing.SwingConstants})
+ * @param shadowX
+ * the shadow's X offset
+ * @param shadowY
+ * the shadow's Y offset
+ * @param shadowColor
+ * the shadow color
+ * @param shadowThickness
+ * the shadow thickness
+ * @param outlineColor
+ * the outline color
+ * @param outlineThickness
+ * the outline thickness
+ */
+ def drawFancyString(posX: Int, posY: Int, str: String, fontFamily: String, fontStyle: Int, fontSize: Int, color: Color, halign: Int, valign: Int, shadowX: Int, shadowY: Int, shadowColor: Color, shadowThickness: Int, outlineColor: Color, outlineThickness: Int): Unit
+
/**
* Draw a centered picture from a file (gif, jpg, png) to (posX, posY)
*
@@ -289,4 +409,10 @@ trait Graphics {
* @return the frame height
*/
def getFrameHeight(): Int
+
+ /**
+ * Returns a list of available font names on the device
+ * @return the list of available font names
+ */
+ def getAvailableFonts(): Array[String]
}
\ No newline at end of file
diff --git a/src/main/scala/hevs/graphics/samples/TestDrawString.scala b/src/main/scala/hevs/graphics/samples/TestDrawString.scala
new file mode 100644
index 0000000..4d0a755
--- /dev/null
+++ b/src/main/scala/hevs/graphics/samples/TestDrawString.scala
@@ -0,0 +1,99 @@
+package hevs.graphics.samples
+
+import hevs.graphics.FunGraphics
+
+import java.awt.{Color, Font}
+import java.awt.geom.Rectangle2D
+import javax.swing.SwingConstants
+
+/**
+ * Sample for drawString methods
+ *
+ * @author Louis Heredero
+ */
+object TestDrawString extends App {
+ val HALIGNMENTS: Array[Int] = Array(
+ SwingConstants.LEFT,
+ SwingConstants.CENTER,
+ SwingConstants.RIGHT
+ )
+ val VALIGNMENTS: Array[Int] = Array(
+ SwingConstants.TOP,
+ SwingConstants.CENTER,
+ SwingConstants.BOTTOM
+ )
+ val fg: FunGraphics = new FunGraphics(600, 600, "Test of drawString")
+
+ for (y: Int <- 0 until 3) {
+ for (x: Int <- 0 until 3) {
+ val posX: Int = 25 + x * 100
+ val posY: Int = 25 + y * 100
+
+ fg.setColor(Color.BLACK)
+ fg.drawString(posX, posY, "Test", halign = HALIGNMENTS(x), valign = VALIGNMENTS(y))
+ fg.setColor(Color.RED)
+ fg.drawFilledCircle(posX-2, posY-2, 2)
+ }
+ }
+
+ fg.setColor(Color.BLACK)
+ for (y: Int <- 0 until 3) {
+ for (x: Int <- 0 until 3) {
+ val posX: Int = 350 + x * 100
+ val posY: Int = 25 + y * 100
+
+ fg.drawFancyString(
+ posX,
+ posY,
+ "Test",
+ halign = SwingConstants.CENTER,
+ valign = SwingConstants.CENTER,
+ shadowX = (x-1)*2,
+ shadowY = (y-1)*2,
+ shadowThickness = 1,
+ fontFamily = "Arial",
+ fontStyle = Font.BOLD
+ )
+ }
+ }
+
+
+ for (y: Int <- 0 until 3) {
+ for (x: Int <- 0 until 3) {
+ val posX: Int = 25 + x * 100
+ val posY: Int = 350 + y * 100
+
+ fg.drawFancyString(
+ posX,
+ posY,
+ "Test",
+ halign = SwingConstants.CENTER,
+ valign = SwingConstants.CENTER,
+ shadowThickness = x+y*3,
+ fontFamily = "Arial",
+ fontStyle = Font.BOLD
+ )
+ }
+ }
+
+
+ for (y: Int <- 0 until 3) {
+ for (x: Int <- 0 until 3) {
+ val posX: Int = 350 + x * 100
+ val posY: Int = 350 + y * 100
+
+ fg.drawFancyString(
+ posX,
+ posY,
+ "Test",
+ color = Color.WHITE,
+ halign = SwingConstants.CENTER,
+ valign = SwingConstants.CENTER,
+ outlineThickness = x+y*3,
+ outlineColor = Color.BLACK,
+ fontFamily = "Arial",
+ fontStyle = Font.BOLD
+ )
+ }
+ }
+}