Code Sketch
yadnesh
Category: Programming
import java.awt.BasicStroke
import java.awt.BorderLayout
import java.awt.Color
import java.awt.Cursor
import java.awt.Dimension
import java.awt.FlowLayout
import java.awt.Font
import java.awt.GradientPaint
import java.awt.Graphics
import java.awt.Graphics2D
import java.awt.RenderingHints
import java.awt.geom.AffineTransform
import java.awt.image.BufferedImage
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import java.awt.event.MouseMotionAdapter
import java.io.File
import javax.imageio.ImageIO
import javax.swing.BorderFactory
import javax.swing.DefaultListModel
import javax.swing.JButton
import javax.swing.JComboBox
import javax.swing.JColorChooser
import javax.swing.JFileChooser
import javax.swing.JFrame
import javax.swing.JLabel
import javax.swing.JList
import javax.swing.JOptionPane
import javax.swing.JPanel
import javax.swing.JScrollPane
import javax.swing.JTextField
import javax.swing.ListSelectionModel
import javax.swing.SwingUtilities
import javax.swing.WindowConstants
// ============================================================
// CONSTANTS
// ============================================================
val W = 1000
val H = 600
val CX = 500
val CY = 300
// ============================================================
// COMPONENT REFERENCES
// ============================================================
var frame: JFrame = null
var canvas: JPanel = null
var status: JLabel = null
var list: JList[String] = null
var model: DefaultListModel[String] = null
var writeField: JTextField = null
var searchField: JTextField = null
var toolBox: JComboBox[String] = null
var sizeBox: JComboBox[String] = null
var backgroundBox: JComboBox[String] = null
var styleBox: JComboBox[String] = null
var undoButton: JButton = null
var redoButton: JButton = null
var clearButton: JButton = null
var saveButton: JButton = null
var drawButton: JButton = null
var randomButton: JButton = null
var searchButton: JButton = null
var colorButton: JButton = null
var zoomInButton: JButton = null
var zoomOutButton: JButton = null
var rotateLeftButton: JButton = null
var rotateRightButton: JButton = null
var flipHButton: JButton = null
var flipVButton: JButton = null
var colorizeButton: JButton = null
var shadowButton: JButton = null
var outlineButton: JButton = null
var gridButton: JButton = null
var resetButton: JButton = null
var currentColor = Color.BLACK
var currentTool = "PENCIL"
var brushSize = 6.0f
var zoom = 1.0
var gridOn = false
var shadowOn = false
var outlineOn = false
var mouseDown = false
var lastX = 0
var lastY = 0
var startX = 0
var startY = 0
var undoImage: BufferedImage = null
var redoImage: BufferedImage = null
var currentBackground = "SKY"
var currentStyle = "NORMAL"
// ============================================================
// MAIN IMAGE
// ============================================================
val image =
new BufferedImage(
W,
H,
BufferedImage.TYPE_INT_RGB
)
val g =
image.createGraphics()
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
)
g.setRenderingHint(
RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_SPEED
)
g.setColor(
Color.WHITE
)
g.fillRect(
0,
0,
W,
H
)
// ============================================================
// HELPERS
// ============================================================
def statusText(
text: String
): Unit = {
if (
status != null
) {
status.setText(text)
}
}
def repaintCanvas(): Unit = {
if (
canvas != null
) {
canvas.repaint()
}
}
def clearCanvasImage(): Unit = {
g.setColor(
Color.WHITE
)
g.fillRect(
0,
0,
W,
H
)
}
def copyImage(
src: BufferedImage
): BufferedImage = {
val dst =
new BufferedImage(
W,
H,
BufferedImage.TYPE_INT_RGB
)
val cg =
dst.createGraphics()
cg.drawImage(
src,
0,
0,
null
)
cg.dispose()
dst
}
def remember(): Unit = {
undoImage =
copyImage(
image
)
redoImage =
null
}
def restore(
src: BufferedImage
): Unit = {
clearCanvasImage()
g.drawImage(
src,
0,
0,
null
)
repaintCanvas()
}
def button(
text: String
): JButton = {
val b =
new JButton(
text
)
b.setFocusable(
false
)
b.setFont(
new Font(
"Arial",
Font.BOLD,
11
)
)
b
}
// ============================================================
// CANVAS MAPPING
// ============================================================
def drawW(): Int = {
math.max(
1,
(W * zoom).toInt
)
}
def drawH(): Int = {
math.max(
1,
(H * zoom).toInt
)
}
def canvasLeft(): Int = {
(
canvas.getWidth -
drawW()
) / 2
}
def canvasTop(): Int = {
(
canvas.getHeight -
drawH()
) / 2
}
def toImageX(
x: Int
): Int = {
val v =
(
(x - canvasLeft()) /
zoom
).toInt
math.max(
0,
math.min(
W - 1,
v
)
)
}
def toImageY(
y: Int
): Int = {
val v =
(
(y - canvasTop()) /
zoom
).toInt
math.max(
0,
math.min(
H - 1,
v
)
)
}
def inside(
x: Int,
y: Int
): Boolean = {
x >= canvasLeft() &&
x < canvasLeft() + drawW() &&
y >= canvasTop() &&
y < canvasTop() + drawH()
}
// ============================================================
// BACKGROUND COLORS
// ============================================================
def bgColors(
name: String
): Array[Color] = {
val t =
name.toUpperCase
if (
t == "SUNSET"
) {
Array(
new Color(255,110,75),
new Color(95,45,155)
)
} else if (
t == "SUNRISE"
) {
Array(
new Color(255,180,95),
new Color(255,235,170)
)
} else if (
t == "NIGHT"
) {
Array(
new Color(10,20,65),
new Color(65,45,125)
)
} else if (
t == "SPACE"
) {
Array(
new Color(3,5,25),
new Color(75,10,115)
)
} else if (
t == "OCEAN"
) {
Array(
new Color(80,215,255),
new Color(10,85,185)
)
} else if (
t == "FOREST"
) {
Array(
new Color(180,235,195),
new Color(45,140,70)
)
} else if (
t == "DESERT"
) {
Array(
new Color(255,220,145),
new Color(205,145,80)
)
} else if (
t == "MAGIC"
) {
Array(
new Color(220,190,255),
new Color(100,50,170)
)
} else if (
t == "NEON"
) {
Array(
new Color(20,20,75),
new Color(120,0,150)
)
} else if (
t == "GOLD"
) {
Array(
new Color(255,235,140),
new Color(200,145,35)
)
} else {
Array(
new Color(165,225,255),
new Color(105,195,115)
)
}
}
// ============================================================
// BACKGROUND DRAWING
// ============================================================
def drawBackground(
name: String
): Unit = {
val colors =
bgColors(
name
)
g.setPaint(
new GradientPaint(
0,
0,
colors(0),
0,
H,
colors(1)
)
)
g.fillRect(
0,
0,
W,
H
)
val t =
name.toUpperCase
if (
t == "SKY" ||
t == "SUNNY" ||
t == "SUNRISE" ||
t == "SUNSET"
) {
g.setColor(
new Color(
255,
215,
60
)
)
g.fillOval(
820,
40,
100,
100
)
}
if (
t == "NIGHT" ||
t == "SPACE" ||
t == "MAGIC"
) {
g.setColor(
Color.WHITE
)
var i =
0
while (
i < 90
) {
val sx =
(i * 83) % W
val sy =
(i * 47) % 450
val ss =
2 + (i % 4)
g.fillOval(
sx,
sy,
ss,
ss
)
i += 1
}
}
if (
t == "FOREST"
) {
g.setColor(
new Color(
70,
155,
75
)
)
g.fillRect(
0,
490,
W,
110
)
}
if (
t == "OCEAN"
) {
g.setColor(
new Color(
20,
115,
185
)
)
g.fillRect(
0,
480,
W,
120
)
}
if (
t == "DESERT"
) {
g.setColor(
new Color(
225,
175,
95
)
)
g.fillOval(
0,
450,
450,
160
)
g.fillOval(
400,
430,
600,
180
)
}
if (
t == "SPACE"
) {
g.setColor(
new Color(
70,
135,
240
)
)
g.fillOval(
380,
180,
240,
240
)
}
}
// ============================================================
// DETAIL EFFECTS
// ============================================================
def applyEffects(
style: String
): Unit = {
if (
shadowOn
) {
g.setColor(
new Color(
0,
0,
0,
65
)
)
g.setStroke(
new BasicStroke(
10
)
)
g.drawRoundRect(
18,
18,
964,
564,
25,
25
)
}
if (
outlineOn
) {
g.setColor(
new Color(
20,
20,
20,
180
)
)
g.setStroke(
new BasicStroke(
5
)
)
g.drawRoundRect(
8,
8,
984,
584,
25,
25
)
}
if (
style == "NEON"
) {
g.setColor(
new Color(
0,
255,
255,
150
)
)
g.setStroke(
new BasicStroke(
10
)
)
g.drawRoundRect(
12,
12,
976,
576,
25,
25
)
}
if (
style == "GOLD"
) {
g.setColor(
new Color(
255,
215,
70,
170
)
)
g.setStroke(
new BasicStroke(
10
)
)
g.drawRoundRect(
12,
12,
976,
576,
25,
25
)
}
if (
style == "MAGIC"
) {
g.setColor(
Color.WHITE
)
var i =
0
while (
i < 55
) {
g.fillOval(
(i * 91) % W,
(i * 53) % H,
5,
5
)
i += 1
}
}
}
// ============================================================
// CAR
// ============================================================
def car(): Unit = {
drawBackground(
currentBackground
)
g.setColor(
new Color(
220,
45,
55
)
)
g.fillRoundRect(
220,
300,
560,
120,
35,
35
)
val roof =
new java.awt.Polygon()
roof.addPoint(
320,
300
)
roof.addPoint(
410,
185
)
roof.addPoint(
600,
185
)
roof.addPoint(
690,
300
)
g.fillPolygon(
roof
)
g.setColor(
new Color(
100,
205,
240
)
)
g.fillRect(
355,
215,
105,
70
)
g.fillRect(
480,
215,
105,
70
)
g.setColor(
Color.BLACK
)
g.fillOval(
275,
370,
100,
100
)
g.fillOval(
625,
370,
100,
100
)
g.setColor(
Color.LIGHT_GRAY
)
g.fillOval(
310,
405,
30,
30
)
g.fillOval(
660,
405,
30,
30
)
applyEffects(
currentStyle
)
}
// ============================================================
// HOUSE
// ============================================================
def house(): Unit = {
drawBackground(
currentBackground
)
g.setColor(
new Color(
245,
205,
125
)
)
g.fillRect(
300,
235,
400,
255
)
val roof =
new java.awt.Polygon()
roof.addPoint(
245,
235
)
roof.addPoint(
500,
50
)
roof.addPoint(
755,
235
)
g.setColor(
new Color(
180,
55,
45
)
)
g.fillPolygon(
roof
)
g.setColor(
new Color(
120,
75,
45
)
)
g.fillRect(
450,
345,
100,
145
)
g.setColor(
new Color(
85,
195,
240
)
)
g.fillRect(
330,
285,
80,
75
)
g.fillRect(
590,
285,
80,
75
)
applyEffects(
currentStyle
)
}
// ============================================================
// TREE
// ============================================================
def tree(): Unit = {
drawBackground(
currentBackground
)
g.setColor(
new Color(
135,
82,
45
)
)
g.fillRoundRect(
455,
275,
90,
225,
25,
25
)
g.setColor(
new Color(
40,
170,
70
)
)
g.fillOval(
290,
115,
240,
190
)
g.fillOval(
470,
90,
240,
220
)
g.fillOval(
380,
35,
240,
220
)
applyEffects(
currentStyle
)
}
// ============================================================
// PERSON
// ============================================================
def person(): Unit = {
drawBackground(
currentBackground
)
g.setColor(
new Color(
245,
195,
150
)
)
g.fillOval(
430,
75,
140,
150
)
g.setColor(
new Color(
50,
35,
25
)
)
g.fillArc(
425,
55,
150,
90,
0,
180
)
g.setColor(
Color.BLACK
)
g.fillOval(
465,
135,
14,
14
)
g.fillOval(
520,
135,
14,
14
)
g.setColor(
new Color(
55,
125,
215
)
)
g.fillRoundRect(
395,
220,
210,
185,
30,
30
)
g.setColor(
new Color(
245,
195,
150
)
)
g.setStroke(
new BasicStroke(
24,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND
)
)
g.drawLine(
415,
260,
315,
395
)
g.drawLine(
585,
260,
685,
395
)
g.setColor(
new Color(
50,
50,
60
)
)
g.setStroke(
new BasicStroke(
38,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND
)
)
g.drawLine(
465,
405,
455,
535
)
g.drawLine(
535,
405,
545,
535
)
applyEffects(
currentStyle
)
}
// ============================================================
// CAT
// ============================================================
def cat(): Unit = {
drawBackground(
currentBackground
)
g.setColor(
new Color(
180,
180,
190
)
)
g.fillOval(
350,
275,
300,
220
)
g.fillOval(
365,
120,
270,
220
)
val e1 =
new java.awt.Polygon()
e1.addPoint(
385,
170
)
e1.addPoint(
425,
65
)
e1.addPoint(
475,
145
)
g.fillPolygon(
e1
)
val e2 =
new java.awt.Polygon()
e2.addPoint(
615,
170
)
e2.addPoint(
575,
65
)
e2.addPoint(
525,
145
)
g.fillPolygon(
e2
)
g.setColor(
new Color(
65,
185,
95
)
)
g.fillOval(
430,
205,
45,
45
)
g.fillOval(
525,
205,
45,
45
)
g.setColor(
Color.PINK
)
g.fillOval(
488,
270,
24,
18
)
applyEffects(
currentStyle
)
}
// ============================================================
// DOG
// ============================================================
def dog(): Unit = {
drawBackground(
currentBackground
)
g.setColor(
new Color(
180,
120,
70
)
)
g.fillOval(
345,
275,
310,
205
)
g.fillOval(
365,
125,
270,
230
)
g.setColor(
new Color(
120,
75,
45
)
)
g.fillOval(
330,
165,
80,
155
)
g.fillOval(
590,
165,
80,
155
)
g.setColor(
Color.BLACK
)
g.fillOval(
430,
215,
23,
25
)
g.fillOval(
548,
215,
23,
25
)
g.fillOval(
478,
275,
45,
32
)
applyEffects(
currentStyle
)
}
// ============================================================
// BIRD
// ============================================================
def bird(): Unit = {
drawBackground(
currentBackground
)
g.setColor(
new Color(
60,
130,
225
)
)
g.fillOval(
335,
255,
300,
190
)
g.fillOval(
545,
165,
140,
130
)
g.setColor(
Color.BLACK
)
g.fillOval(
630,
205,
18,
18
)
g.setColor(
Color.ORANGE
)
val beak =
new java.awt.Polygon()
beak.addPoint(
680,
225
)
beak.addPoint(
755,
255
)
beak.addPoint(
680,
280
)
g.fillPolygon(
beak
)
applyEffects(
currentStyle
)
}
// ============================================================
// FISH
// ============================================================
def fish(): Unit = {
drawBackground(
currentBackground
)
g.setColor(
new Color(
60,
155,
230
)
)
g.fillOval(
295,
220,
390,
190
)
val tail =
new java.awt.Polygon()
tail.addPoint(
660,
315
)
tail.addPoint(
790,
220
)
tail.addPoint(
790,
410
)
g.fillPolygon(
tail
)
g.setColor(
Color.BLACK
)
g.fillOval(
365,
280,
23,
23
)
applyEffects(
currentStyle
)
}
// ============================================================
// FLOWER
// ============================================================
def flower(): Unit = {
drawBackground(
currentBackground
)
g.setColor(
new Color(
45,
155,
60
)
)
g.setStroke(
new BasicStroke(
15,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND
)
)
g.drawLine(
500,
280,
500,
515
)
val petals =
Array(
Color.RED,
Color.PINK,
Color.MAGENTA,
Color.ORANGE,
new Color(145,80,220),
new Color(255,80,120)
)
var i =
0
while (
i < 6
) {
val a =
i * math.Pi / 3.0
val x =
500 +
(math.cos(a) * 80).toInt -
50
val y =
220 +
(math.sin(a) * 80).toInt -
50
g.setColor(
petals(i)
)
g.fillOval(
x,
y,
100,
100
)
i += 1
}
g.setColor(
Color.YELLOW
)
g.fillOval(
450,
170,
100,
100
)
applyEffects(
currentStyle
)
}
// ============================================================
// STAR
// ============================================================
def star(): Unit = {
drawBackground(
currentBackground
)
val p =
new java.awt.Polygon()
var i =
0
while (
i < 10
) {
val a =
-math.Pi / 2 +
i * math.Pi / 5.0
val r =
if (
i % 2 == 0
) {
190.0
} else {
82.0
}
p.addPoint(
CX +
(math.cos(a) * r).toInt,
CY +
(math.sin(a) * r).toInt
)
i += 1
}
g.setColor(
new Color(
255,
210,
0
)
)
g.fillPolygon(
p
)
applyEffects(
currentStyle
)
}
// ============================================================
// HEART
// ============================================================
def heart(): Unit = {
drawBackground(
currentBackground
)
val p =
new java.awt.geom.Path2D.Double()
p.moveTo(
CX,
CY + 190
)
p.curveTo(
CX - 270,
CY + 20,
CX - 170,
CY - 175,
CX,
CY - 45
)
p.curveTo(
CX + 170,
CY - 175,
CX + 270,
CY + 20,
CX,
CY + 190
)
g.setColor(
Color.RED
)
g.fill(
p
)
applyEffects(
currentStyle
)
}
// ============================================================
// PIZZA
// ============================================================
def pizza(): Unit = {
drawBackground(
currentBackground
)
val p =
new java.awt.Polygon()
p.addPoint(
500,
115
)
p.addPoint(
800,
480
)
p.addPoint(
200,
480
)
g.setColor(
new Color(
240,
180,
60
)
)
g.fillPolygon(
p
)
g.setColor(
new Color(
220,
55,
55
)
)
g.fillOval(
345,
300,
42,
42
)
g.fillOval(
545,
335,
42,
42
)
g.fillOval(
475,
400,
42,
42
)
applyEffects(
currentStyle
)
}
// ============================================================
// ROCKET
// ============================================================
def rocket(): Unit = {
drawBackground(
"SPACE"
)
g.setColor(
new Color(
220,
220,
230
)
)
g.fillOval(
415,
125,
170,
300
)
g.setColor(
Color.RED
)
val left =
new java.awt.Polygon()
left.addPoint(
415,
340
)
left.addPoint(
350,
430
)
left.addPoint(
415,
415
)
g.fillPolygon(
left
)
val right =
new java.awt.Polygon()
right.addPoint(
585,
340
)
right.addPoint(
650,
430
)
right.addPoint(
585,
415
)
g.fillPolygon(
right
)
g.setColor(
new Color(
80,
170,
235
)
)
g.fillOval(
465,
190,
70,
70
)
g.setColor(
Color.ORANGE
)
g.fillOval(
455,
390,
90,
130
)
applyEffects(
currentStyle
)
}
// ============================================================
// MOUNTAIN
// ============================================================
def mountain(): Unit = {
drawBackground(
"SUNNY"
)
val back =
new java.awt.Polygon()
back.addPoint(
0,
500
)
back.addPoint(
250,
180
)
back.addPoint(
520,
500
)
g.setColor(
new Color(
130,
145,
165
)
)
g.fillPolygon(
back
)
val front =
new java.awt.Polygon()
front.addPoint(
270,
500
)
front.addPoint(
610,
130
)
front.addPoint(
960,
500
)
g.setColor(
new Color(
85,
120,
100
)
)
g.fillPolygon(
front
)
applyEffects(
currentStyle
)
}
// ============================================================
// GENERIC SMART OBJECT
// ============================================================
def genericObject(
item: String
): Unit = {
drawBackground(
currentBackground
)
val hash =
math.abs(
item.hashCode
)
val c =
new Color(
40 + hash % 185,
40 + (hash / 7) % 185,
40 + (hash / 13) % 185
)
g.setColor(
c
)
val typeId =
hash % 6
if (
typeId == 0
) {
g.fillRoundRect(
280,
170,
440,
270,
45,
45
)
} else if (
typeId == 1
) {
g.fillOval(
300,
120,
400,
400
)
} else if (
typeId == 2
) {
val p =
new java.awt.Polygon()
p.addPoint(
500,
90
)
p.addPoint(
750,
480
)
p.addPoint(
250,
480
)
g.fillPolygon(
p
)
} else if (
typeId == 3
) {
g.fillRect(
300,
140,
400,
340
)
} else if (
typeId == 4
) {
val p =
new java.awt.Polygon()
var i =
0
while (
i < 8
) {
val a =
i * math.Pi / 4.0
p.addPoint(
CX +
(math.cos(a) * 190).toInt,
CY +
(math.sin(a) * 190).toInt
)
i += 1
}
g.fillPolygon(
p
)
} else {
val p =
new java.awt.Polygon()
var i =
0
while (
i < 10
) {
val a =
-math.Pi / 2 +
i * math.Pi / 5.0
val r =
if (
i % 2 == 0
) {
190.0
} else {
82.0
}
p.addPoint(
CX +
(math.cos(a) * r).toInt,
CY +
(math.sin(a) * r).toInt
)
i += 1
}
g.fillPolygon(
p
)
}
g.setColor(
Color.BLACK
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
24
)
)
val label =
item.take(
25
)
val tw =
g.getFontMetrics
.stringWidth(
label
)
g.drawString(
label,
CX - tw / 2,
555
)
applyEffects(
currentStyle
)
}
// ============================================================
// EXACT ITEM ROUTER
// ============================================================
def drawItem(
item: String
): Unit = {
val t =
item
.toLowerCase
.trim
if (
t.indexOf("car") >= 0
) {
car()
} else if (
t.indexOf("house") >= 0
) {
house()
} else if (
t.indexOf("tree") >= 0
) {
tree()
} else if (
t.indexOf("person") >= 0 ||
t.indexOf("boy") >= 0 ||
t.indexOf("girl") >= 0 ||
t.indexOf("man") >= 0 ||
t.indexOf("woman") >= 0
) {
person()
} else if (
t.indexOf("cat") >= 0
) {
cat()
} else if (
t.indexOf("dog") >= 0
) {
dog()
} else if (
t.indexOf("bird") >= 0
) {
bird()
} else if (
t.indexOf("fish") >= 0
) {
fish()
} else if (
t.indexOf("flower") >= 0 ||
t.indexOf("rose") >= 0
) {
flower()
} else if (
t.indexOf("star") >= 0
) {
star()
} else if (
t.indexOf("heart") >= 0
) {
heart()
} else if (
t.indexOf("pizza") >= 0
) {
pizza()
} else if (
t.indexOf("rocket") >= 0
) {
rocket()
} else if (
t.indexOf("mountain") >= 0
) {
mountain()
} else {
genericObject(
item
)
}
writeField.setText(
item
)
statusText(
"DRAWN: " +
item
)
repaintCanvas()
}
// ============================================================
// 30 THINGS
// ============================================================
val things =
Array(
"car",
"house",
"tree",
"boy",
"girl",
"man",
"woman",
"cat",
"dog",
"bird",
"fish",
"flower",
"star",
"heart",
"pizza",
"rocket",
"mountain",
"robot",
"lion",
"elephant",
"horse",
"rabbit",
"apple",
"banana",
"football",
"cricket bat",
"guitar",
"computer",
"camera",
"pencil"
)
model =
new DefaultListModel[String]()
var ti =
0
while (
ti < things.length
) {
model.addElement(
things(ti)
)
ti += 1
}
// ============================================================
// MAIN FRAME
// ============================================================
frame =
new JFrame(
"ULTRA 30 SMART DRAW STUDIO"
)
frame.setDefaultCloseOperation(
WindowConstants.EXIT_ON_CLOSE
)
frame.setSize(
1400,
850
)
frame.setLocationRelativeTo(
null
)
// ============================================================
// STATUS
// ============================================================
status =
new JLabel(
"READY"
)
status.setFont(
new Font(
"Arial",
Font.BOLD,
15
)
)
// ============================================================
// CANVAS
// ============================================================
canvas =
new JPanel {
override def paintComponent(
graphics: Graphics
): Unit = {
super.paintComponent(
graphics
)
val gg =
graphics.asInstanceOf[
Graphics2D
]
gg.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
)
val dw =
math.max(
1,
(W * zoom).toInt
)
val dh =
math.max(
1,
(H * zoom).toInt
)
val ox =
(getWidth - dw) / 2
val oy =
(getHeight - dh) / 2
gg.setColor(
new Color(
235,
235,
235
)
)
gg.fillRect(
0,
0,
getWidth,
getHeight
)
gg.drawImage(
image,
ox,
oy,
dw,
dh,
null
)
if (
gridOn
) {
gg.setColor(
new Color(
0,
0,
0,
25
)
)
val step =
math.max(
25,
(50 * zoom).toInt
)
var x =
ox
while (
x <= ox + dw
) {
gg.drawLine(
x,
oy,
x,
oy + dh
)
x += step
}
var y =
oy
while (
y <= oy + dh
) {
gg.drawLine(
ox,
y,
ox + dw,
y
)
y += step
}
}
}
}
canvas.setFocusable(
true
)
canvas.setCursor(
Cursor.getPredefinedCursor(
Cursor.CROSSHAIR_CURSOR
)
)
// ============================================================
// RIGHT SIDE LIST
// ============================================================
list =
new JList[String](
model
)
list.setSelectionMode(
ListSelectionModel.SINGLE_SELECTION
)
list.setFont(
new Font(
"Arial",
Font.PLAIN,
15
)
)
val listScroll =
new JScrollPane(
list
)
listScroll.setPreferredSize(
new Dimension(
280,
620
)
)
// ============================================================
// SEARCH
// ============================================================
searchField =
new JTextField(
10
)
searchButton =
button(
"SEARCH"
)
def searchItems(): Unit = {
val q =
searchField
.getText
.trim
.toLowerCase
model.clear()
var i =
0
while (
i < things.length
) {
if (
q.length == 0 ||
things(i)
.toLowerCase
.indexOf(q) >= 0
) {
model.addElement(
things(i)
)
}
i += 1
}
statusText(
"SEARCH COMPLETE"
)
}
searchButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
searchItems()
}
}
)
// ============================================================
// RIGHT PANEL
// ============================================================
val rightTitle =
new JLabel(
"30 THINGS"
)
rightTitle.setFont(
new Font(
"Arial",
Font.BOLD,
20
)
)
val rightInfo =
new JLabel(
"CLICK = DRAW"
)
rightInfo.setFont(
new Font(
"Arial",
Font.BOLD,
11
)
)
val searchPanel =
new JPanel(
new FlowLayout(
FlowLayout.LEFT,
3,
3
)
)
searchPanel.add(
searchField
)
searchPanel.add(
searchButton
)
val rightTop =
new JPanel(
new BorderLayout()
)
rightTop.add(
rightTitle,
BorderLayout.NORTH
)
rightTop.add(
rightInfo,
BorderLayout.CENTER
)
rightTop.add(
searchPanel,
BorderLayout.SOUTH
)
val rightPanel =
new JPanel(
new BorderLayout(
4,
4
)
)
rightPanel.setBorder(
BorderFactory.createEmptyBorder(
5,
5,
5,
5
)
)
rightPanel.add(
rightTop,
BorderLayout.NORTH
)
rightPanel.add(
listScroll,
BorderLayout.CENTER
)
// ============================================================
// BUTTONS
// ============================================================
undoButton =
button(
"UNDO"
)
redoButton =
button(
"REDO"
)
clearButton =
button(
"CLEAR"
)
saveButton =
button(
"SAVE"
)
drawButton =
button(
"DRAW IT"
)
randomButton =
button(
"RANDOM"
)
zoomInButton =
button(
"ZOOM +"
)
zoomOutButton =
button(
"ZOOM -"
)
rotateLeftButton =
button(
"ROTATE L"
)
rotateRightButton =
button(
"ROTATE R"
)
flipHButton =
button(
"FLIP H"
)
flipVButton =
button(
"FLIP V"
)
colorizeButton =
button(
"COLORIZE"
)
shadowButton =
button(
"SHADOW"
)
outlineButton =
button(
"OUTLINE"
)
gridButton =
button(
"GRID"
)
resetButton =
button(
"RESET"
)
colorButton =
button(
"CUSTOM COLOR"
)
// ============================================================
// COMBO BOXES
// ============================================================
toolBox =
new JComboBox[String](
Array(
"PENCIL",
"ERASER",
"LINE",
"RECTANGLE",
"ELLIPSE",
"SPRAY"
)
)
sizeBox =
new JComboBox[String](
Array(
"2",
"4",
"6",
"8",
"10",
"14",
"18",
"24",
"30",
"40",
"50"
)
)
sizeBox.setSelectedItem(
"6"
)
backgroundBox =
new JComboBox[String](
Array(
"SKY",
"SUNNY",
"SUNRISE",
"SUNSET",
"NIGHT",
"SPACE",
"OCEAN",
"FOREST",
"DESERT",
"MAGIC",
"NEON",
"GOLD"
)
)
styleBox =
new JComboBox[String](
Array(
"NORMAL",
"3D",
"NEON",
"MAGIC",
"GOLD"
)
)
writeField =
new JTextField(
"car",
12
)
// ============================================================
// TOOLBAR
// ============================================================
val toolbar =
new JPanel(
new FlowLayout(
FlowLayout.LEFT,
4,
4
)
)
toolbar.add(undoButton)
toolbar.add(redoButton)
toolbar.add(clearButton)
toolbar.add(saveButton)
toolbar.add(drawButton)
toolbar.add(randomButton)
toolbar.add(
new JLabel(
"WRITE:"
)
)
toolbar.add(
writeField
)
toolbar.add(
new JLabel(
"TOOL:"
)
)
toolbar.add(
toolBox
)
toolbar.add(
new JLabel(
"SIZE:"
)
)
toolbar.add(
sizeBox
)
toolbar.add(
colorButton
)
toolbar.add(colorizeButton)
toolbar.add(
new JLabel(
"BG:"
)
)
toolbar.add(
backgroundBox
)
toolbar.add(
new JLabel(
"STYLE:"
)
)
toolbar.add(
styleBox
)
toolbar.add(shadowButton)
toolbar.add(outlineButton)
toolbar.add(gridButton)
toolbar.add(zoomInButton)
toolbar.add(zoomOutButton)
toolbar.add(rotateLeftButton)
toolbar.add(rotateRightButton)
toolbar.add(flipHButton)
toolbar.add(flipVButton)
toolbar.add(resetButton)
// ============================================================
// COLORS
// ============================================================
def addColorButton(
c: Color
): Unit = {
val b =
new JButton(
" "
)
b.setPreferredSize(
new Dimension(
22,
22
)
)
b.setBackground(
c
)
b.setOpaque(
true
)
b.setFocusable(
false
)
b.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
currentColor =
c
toolBox.setSelectedItem(
"PENCIL"
)
currentTool =
"PENCIL"
statusText(
"COLOR SELECTED"
)
}
}
)
toolbar.add(
b
)
}
addColorButton(Color.BLACK)
addColorButton(Color.RED)
addColorButton(Color.BLUE)
addColorButton(Color.GREEN)
addColorButton(Color.YELLOW)
addColorButton(Color.ORANGE)
addColorButton(Color.MAGENTA)
addColorButton(Color.CYAN)
addColorButton(Color.PINK)
addColorButton(new Color(128,64,0))
colorButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
val c =
JColorChooser.showDialog(
frame,
"CUSTOM COLOR",
currentColor
)
if (
c != null
) {
currentColor =
c
currentTool =
"PENCIL"
toolBox.setSelectedItem(
"PENCIL"
)
}
}
}
)
// ============================================================
// TOOL SELECTION
// ============================================================
toolBox.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
val v =
toolBox
.getSelectedItem
if (
v != null
) {
currentTool =
v.toString
}
}
}
)
sizeBox.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
try {
brushSize =
sizeBox
.getSelectedItem
.toString
.toFloat
} catch {
case _: Exception =>
}
}
}
)
backgroundBox.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
currentBackground =
backgroundBox
.getSelectedItem
.toString
}
}
)
styleBox.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
currentStyle =
styleBox
.getSelectedItem
.toString
}
}
)
// ============================================================
// LIST CLICK = EXACT DRAW
// ============================================================
list.addMouseListener(
new MouseAdapter {
override def mouseClicked(
e: MouseEvent
): Unit = {
val index =
list.locationToIndex(
e.getPoint
)
if (
index >= 0
) {
val bounds =
list.getCellBounds(
index,
index
)
if (
bounds != null &&
bounds.contains(
e.getPoint
)
) {
val item =
list.getModel
.getElementAt(
index
)
remember()
drawItem(
item
)
}
}
}
}
)
// ============================================================
// DRAW BUTTON
// ============================================================
drawButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
val text =
writeField
.getText
.trim
if (
text.length > 0
) {
remember()
drawItem(
text
)
}
}
}
)
// ============================================================
// ENTER
// ============================================================
writeField.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
drawButton.doClick()
}
}
)
// ============================================================
// RANDOM
// ============================================================
val rng =
new scala.util.Random()
randomButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
val index =
rng.nextInt(
things.length
)
val item =
things(index)
writeField.setText(
item
)
remember()
drawItem(
item
)
}
}
)
// ============================================================
// UNDO
// ============================================================
undoButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
if (
undoImage != null
) {
redoImage =
copyImage(
image
)
restore(
undoImage
)
undoImage =
null
statusText(
"UNDO"
)
}
}
}
)
// ============================================================
// REDO
// ============================================================
redoButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
if (
redoImage != null
) {
undoImage =
copyImage(
image
)
restore(
redoImage
)
redoImage =
null
statusText(
"REDO"
)
}
}
}
)
// ============================================================
// CLEAR
// ============================================================
clearButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
remember()
clearCanvasImage()
repaintCanvas()
statusText(
"CANVAS CLEARED"
)
}
}
)
// ============================================================
// SAVE
// ============================================================
saveButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
val chooser =
new JFileChooser()
if (
chooser.showSaveDialog(
frame
) ==
JFileChooser.APPROVE_OPTION
) {
try {
var f =
chooser.getSelectedFile
if (
!f.getName
.toLowerCase
.endsWith(".png")
) {
f =
new File(
f.getAbsolutePath +
".png"
)
}
ImageIO.write(
image,
"png",
f
)
statusText(
"IMAGE SAVED"
)
} catch {
case ex: Exception =>
JOptionPane.showMessageDialog(
frame,
ex.getMessage,
"SAVE ERROR",
JOptionPane.ERROR_MESSAGE
)
}
}
}
}
)
// ============================================================
// ZOOM
// ============================================================
zoomInButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
zoom =
math.min(
2.5,
zoom + 0.10
)
repaintCanvas()
}
}
)
zoomOutButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
zoom =
math.max(
0.50,
zoom - 0.10
)
repaintCanvas()
}
}
)
// ============================================================
// ROTATION
// ============================================================
def rotateImage(
angle: Double
): Unit = {
remember()
val rotated =
new BufferedImage(
W,
H,
BufferedImage.TYPE_INT_RGB
)
val rg =
rotated.createGraphics()
rg.setColor(
Color.WHITE
)
rg.fillRect(
0,
0,
W,
H
)
val at =
new AffineTransform()
at.translate(
W / 2.0,
H / 2.0
)
at.rotate(
angle
)
at.translate(
-W / 2.0,
-H / 2.0
)
rg.drawImage(
image,
at,
null
)
rg.dispose()
restore(
rotated
)
}
rotateLeftButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
rotateImage(
-math.Pi / 2
)
}
}
)
rotateRightButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
rotateImage(
math.Pi / 2
)
}
}
)
// ============================================================
// FLIP
// ============================================================
def flipImage(
horizontal: Boolean
): Unit = {
remember()
val flipped =
new BufferedImage(
W,
H,
BufferedImage.TYPE_INT_RGB
)
val fg =
flipped.createGraphics()
if (
horizontal
) {
fg.drawImage(
image,
W,
0,
-W,
H,
null
)
} else {
fg.drawImage(
image,
0,
H,
W,
-H,
null
)
}
fg.dispose()
restore(
flipped
)
}
flipHButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
flipImage(
true
)
}
}
)
flipVButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
flipImage(
false
)
}
}
)
// ============================================================
// SHADOW
// ============================================================
shadowButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
shadowOn =
!shadowOn
statusText(
if (
shadowOn
) {
"SHADOW ON"
} else {
"SHADOW OFF"
}
)
}
}
)
// ============================================================
// OUTLINE
// ============================================================
outlineButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
outlineOn =
!outlineOn
statusText(
if (
outlineOn
) {
"OUTLINE ON"
} else {
"OUTLINE OFF"
}
)
}
}
)
// ============================================================
// GRID
// ============================================================
gridButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
gridOn =
!gridOn
repaintCanvas()
}
}
)
// ============================================================
// RESET
// ============================================================
resetButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
zoom =
1.0
gridOn =
false
shadowOn =
false
outlineOn =
false
currentBackground =
"SKY"
currentStyle =
"NORMAL"
backgroundBox.setSelectedItem(
"SKY"
)
styleBox.setSelectedItem(
"NORMAL"
)
repaintCanvas()
statusText(
"VIEW RESET"
)
}
}
)
// ============================================================
// COLORIZE
// ============================================================
colorizeButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
remember()
val selected =
backgroundBox
.getSelectedItem
.toString
currentBackground =
selected
val selectedStyle =
styleBox
.getSelectedItem
.toString
currentStyle =
selectedStyle
val item =
writeField
.getText
.trim
if (
item.length > 0
) {
drawItem(
item
)
} else {
drawBackground(
currentBackground
)
repaintCanvas()
}
statusText(
"COLORIZE COMPLETE"
)
}
}
)
// ============================================================
// MOUSE DRAW
// ============================================================
canvas.addMouseListener(
new MouseAdapter {
override def mousePressed(
e: MouseEvent
): Unit = {
if (
!inside(
e.getX,
e.getY
)
) {
mouseDown =
false
return
}
remember()
mouseDown =
true
startX =
toImageX(
e.getX
)
startY =
toImageY(
e.getY
)
lastX =
startX
lastY =
startY
if (
currentTool ==
"PENCIL"
) {
g.setColor(
currentColor
)
g.setStroke(
new BasicStroke(
brushSize,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND
)
)
g.drawLine(
startX,
startY,
startX,
startY
)
}
if (
currentTool ==
"ERASER"
) {
g.setColor(
Color.WHITE
)
g.setStroke(
new BasicStroke(
brushSize,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND
)
)
g.drawLine(
startX,
startY,
startX,
startY
)
}
repaintCanvas()
}
override def mouseReleased(
e: MouseEvent
): Unit = {
if (
!mouseDown
) {
return
}
val ex =
toImageX(
e.getX
)
val ey =
toImageY(
e.getY
)
if (
currentTool ==
"LINE"
) {
g.setColor(
currentColor
)
g.setStroke(
new BasicStroke(
brushSize,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND
)
)
g.drawLine(
startX,
startY,
ex,
ey
)
}
if (
currentTool ==
"RECTANGLE"
) {
g.setColor(
currentColor
)
g.setStroke(
new BasicStroke(
brushSize
)
)
g.drawRect(
math.min(
startX,
ex
),
math.min(
startY,
ey
),
math.abs(
ex -
startX
),
math.abs(
ey -
startY
)
)
}
if (
currentTool ==
"ELLIPSE"
) {
g.setColor(
currentColor
)
g.setStroke(
new BasicStroke(
brushSize
)
)
g.drawOval(
math.min(
startX,
ex
),
math.min(
startY,
ey
),
math.abs(
ex -
startX
),
math.abs(
ey -
startY
)
)
}
mouseDown =
false
repaintCanvas()
}
}
)
// ============================================================
// MOUSE DRAG
// ============================================================
canvas.addMouseMotionListener(
new MouseMotionAdapter {
override def mouseDragged(
e: MouseEvent
): Unit = {
if (
!mouseDown
) {
return
}
if (
!inside(
e.getX,
e.getY
)
) {
return
}
val x =
toImageX(
e.getX
)
val y =
toImageY(
e.getY
)
if (
currentTool ==
"PENCIL"
) {
g.setColor(
currentColor
)
g.setStroke(
new BasicStroke(
brushSize,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND
)
)
g.drawLine(
lastX,
lastY,
x,
y
)
}
if (
currentTool ==
"ERASER"
) {
g.setColor(
Color.WHITE
)
g.setStroke(
new BasicStroke(
brushSize,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND
)
)
g.drawLine(
lastX,
lastY,
x,
y
)
}
if (
currentTool ==
"SPRAY"
) {
g.setColor(
currentColor
)
var s =
0
while (
s < 12
) {
val dx =
((s * 17) % 20) - 10
val dy =
((s * 29) % 20) - 10
g.fillOval(
x + dx,
y + dy,
2,
2
)
s += 1
}
}
lastX =
x
lastY =
y
repaintCanvas()
}
}
)
// ============================================================
// BOTTOM BAR
// ============================================================
val bottom =
new JPanel(
new FlowLayout(
FlowLayout.LEFT,
8,
5
)
)
bottom.add(
status
)
bottom.add(
new JLabel(
"30 OBJECTS | CLICK ITEM = DRAW | WRITE + DRAW | ZOOM | ROTATE | FLIP | COLORIZE | GRID"
)
)
// ============================================================
// FINAL LAYOUT
// ============================================================
frame.setLayout(
new BorderLayout(
4,
4
)
)
frame.add(
toolbar,
BorderLayout.NORTH
)
frame.add(
canvas,
BorderLayout.CENTER
)
frame.add(
rightPanel,
BorderLayout.EAST
)
frame.add(
bottom,
BorderLayout.SOUTH
)
// ============================================================
// START
// ============================================================
SwingUtilities.invokeLater(
new Runnable {
override def run(): Unit = {
frame.setVisible(
true
)
canvas.requestFocusInWindow()
statusText(
"READY - CLICK ANY OF THE 30 THINGS"
)
}
}
)