Code Sketch


yoooo...........
By: Mhalsakant School
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.event.ActionEvent
import java.awt.event.ActionListener
import java.awt.event.KeyEvent
import java.awt.event.KeyAdapter
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import java.awt.event.MouseMotionAdapter

import java.awt.image.BufferedImage

import java.io.File

import javax.imageio.ImageIO

import javax.swing.JButton
import javax.swing.JComboBox
import javax.swing.JFileChooser
import javax.swing.JFrame
import javax.swing.JLabel
import javax.swing.JOptionPane
import javax.swing.JPanel
import javax.swing.JTextField
import javax.swing.SwingUtilities
import javax.swing.Timer
import javax.swing.WindowConstants


// ============================================================
//                    SAFE CONSTANTS
// ============================================================

val CANVAS_WIDTH =
  1000

val CANVAS_HEIGHT =
  600

val CENTER_X =
  500

val CENTER_Y =
  300


// ============================================================
//                    APPLICATION STATE
// ============================================================

var currentColor =
  Color.BLACK

var brushSize =
  6.0f

var eraserMode =
  false

var isDrawing =
  false

var lastX =
  0

var lastY =
  0

var zoomLevel =
  1.0

var currentTheme =
  "SKY"

var currentStyle =
  "3D"


var undoImage:
  BufferedImage = null

var redoImage:
  BufferedImage = null


// ============================================================
//                    MAIN FRAME
// ============================================================

val frame =
  new JFrame(
    "ULTRA LEGEND SMART DRAW"
  )

frame.setDefaultCloseOperation(
  WindowConstants.EXIT_ON_CLOSE
)

frame.setSize(
  1200,
  820
)

frame.setLocationRelativeTo(
  null
)


// ============================================================
//                    STATUS LABEL
// ============================================================

val status =
  new JLabel(
    "Ready - draw something!"
  )

status.setFont(
  new Font(
    "Arial",
    Font.BOLD,
    15
  )
)


// ============================================================
//                    DRAWING IMAGE
// ============================================================

val drawingImage =
  new BufferedImage(
    CANVAS_WIDTH,
    CANVAS_HEIGHT,
    BufferedImage.TYPE_INT_RGB
  )

val drawingGraphics =
  drawingImage.createGraphics()

drawingGraphics.setRenderingHint(
  RenderingHints.KEY_ANTIALIASING,
  RenderingHints.VALUE_ANTIALIAS_ON
)

drawingGraphics.setRenderingHint(
  RenderingHints.KEY_RENDERING,
  RenderingHints.VALUE_RENDER_QUALITY
)

drawingGraphics.setColor(
  Color.WHITE
)

drawingGraphics.fillRect(
  0,
  0,
  CANVAS_WIDTH,
  CANVAS_HEIGHT
)


// ============================================================
//                    CANVAS
// ============================================================

val canvas =
  new JPanel {

    override def paintComponent(
      graphics: Graphics
    ): Unit = {

      super.paintComponent(
        graphics
      )

      val g =
        graphics.asInstanceOf[Graphics2D]

      g.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON
      )

      g.setRenderingHint(
        RenderingHints.KEY_INTERPOLATION,
        RenderingHints.VALUE_INTERPOLATION_BICUBIC
      )

      val imageWidth =
        math.max(
          1,
          (CANVAS_WIDTH * zoomLevel).toInt
        )

      val imageHeight =
        math.max(
          1,
          (CANVAS_HEIGHT * zoomLevel).toInt
        )

      val x =
        (getWidth - imageWidth) / 2

      val y =
        (getHeight - imageHeight) / 2

      g.drawImage(
        drawingImage,
        x,
        y,
        imageWidth,
        imageHeight,
        null
      )
    }
  }

canvas.setBackground(
  Color.WHITE
)

canvas.setPreferredSize(
  new Dimension(
    CANVAS_WIDTH,
    CANVAS_HEIGHT
  )
)

canvas.setCursor(
  Cursor.getPredefinedCursor(
    Cursor.CROSSHAIR_CURSOR
  )
)


// ============================================================
//                    BUTTON HELPER
// ============================================================

def makeButton(
  text: String
): JButton = {

  val b =
    new JButton(
      text
    )

  b.setFocusable(
    false
  )

  b.setFont(
    new Font(
      "Arial",
      Font.BOLD,
      12
    )
  )

  b
}


// ============================================================
//                    TOOLBAR
// ============================================================

val toolbar =
  new JPanel(
    new FlowLayout(
      FlowLayout.LEFT,
      4,
      4
    )
  )


val pencilButton =
  makeButton(
    "PENCIL"
  )

val eraserButton =
  makeButton(
    "ERASER"
  )

val undoButton =
  makeButton(
    "UNDO"
  )

val redoButton =
  makeButton(
    "REDO"
  )

val clearButton =
  makeButton(
    "CLEAR"
  )

val saveButton =
  makeButton(
    "SAVE"
  )

val colorizeButton =
  makeButton(
    "COLORIZE"
  )

val threeDButton =
  makeButton(
    "3D PREVIEW"
  )

val zoomInButton =
  makeButton(
    "ZOOM +"
  )

val zoomOutButton =
  makeButton(
    "ZOOM -"
  )

val resetButton =
  makeButton(
    "RESET"
  )

val drawButton =
  makeButton(
    "DRAW IT"
  )


// ============================================================
//                    WRITE FIELD
// ============================================================

val writeField =
  new JTextField(
    "CAR",
    12
  )


// ============================================================
//                    STYLE SELECTOR
// ============================================================

val styleBox =
  new JComboBox[String](
    Array(
      "3D",
      "GLOSSY",
      "NEON",
      "SOFT",
      "COMIC",
      "MAGIC",
      "GOLD"
    )
  )

styleBox.setSelectedItem(
  "3D"
)


// ============================================================
//                    SIZE SELECTOR
// ============================================================

val sizeBox =
  new JComboBox[String](
    Array(
      "2",
      "4",
      "6",
      "8",
      "10",
      "14",
      "18",
      "24",
      "35",
      "50"
    )
  )

sizeBox.setSelectedItem(
  "6"
)


// ============================================================
//                    BUILD TOOLBAR
// ============================================================

toolbar.add(
  pencilButton
)

toolbar.add(
  eraserButton
)

toolbar.add(
  undoButton
)

toolbar.add(
  redoButton
)

toolbar.add(
  clearButton
)

toolbar.add(
  saveButton
)

toolbar.add(
  colorizeButton
)

toolbar.add(
  threeDButton
)

toolbar.add(
  zoomInButton
)

toolbar.add(
  zoomOutButton
)

toolbar.add(
  resetButton
)

toolbar.add(
  new JLabel(
    "WRITE:"
  )
)

toolbar.add(
  writeField
)

toolbar.add(
  drawButton
)

toolbar.add(
  new JLabel(
    "STYLE:"
  )
)

toolbar.add(
  styleBox
)

toolbar.add(
  new JLabel(
    "SIZE:"
  )
)

toolbar.add(
  sizeBox
)

toolbar.add(
  new JLabel(
    "COLORS:"
  )
)


// ============================================================
//                    COLOR PALETTE
// ============================================================

def addColorButton(
  color: Color
): Unit = {

  val b =
    new JButton(
      " "
    )

  b.setPreferredSize(
    new Dimension(
      22,
      22
    )
  )

  b.setBackground(
    color
  )

  b.setOpaque(
    true
  )

  b.setFocusable(
    false
  )

  b.addActionListener(
    new ActionListener {

      override def actionPerformed(
        e: ActionEvent
      ): Unit = {

        currentColor =
          color

        eraserMode =
          false

        status.setText(
          "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
  )
)


// ============================================================
//                    IMAGE COPY
// ============================================================

def copyImage(
  source: BufferedImage
): BufferedImage = {

  val result =
    new BufferedImage(
      CANVAS_WIDTH,
      CANVAS_HEIGHT,
      BufferedImage.TYPE_INT_RGB
    )

  val g =
    result.createGraphics()

  g.drawImage(
    source,
    0,
    0,
    null
  )

  g.dispose()

  result
}


// ============================================================
//                    UNDO MEMORY
// ============================================================

def rememberUndo(): Unit = {

  undoImage =
    copyImage(
      drawingImage
    )

  redoImage =
    null
}


// ============================================================
//                    RESTORE IMAGE
// ============================================================

def restoreImage(
  source: BufferedImage
): Unit = {

  drawingGraphics.setColor(
    Color.WHITE
  )

  drawingGraphics.fillRect(
    0,
    0,
    CANVAS_WIDTH,
    CANVAS_HEIGHT
  )

  drawingGraphics.drawImage(
    source,
    0,
    0,
    null
  )

  canvas.repaint()
}


// ============================================================
//                    CLEAR IMAGE
// ============================================================

def clearImage(): Unit = {

  drawingGraphics.setColor(
    Color.WHITE
  )

  drawingGraphics.fillRect(
    0,
    0,
    CANVAS_WIDTH,
    CANVAS_HEIGHT
  )

  canvas.repaint()
}


// ============================================================
//                    CAR
// ============================================================

def drawCar(): Unit = {

  clearImage()

  val g =
    drawingGraphics

  val cx =
    CENTER_X

  val cy =
    CENTER_Y


  g.setColor(
    new Color(
      220,
      40,
      50
    )
  )

  g.fillRoundRect(
    cx - 270,
    cy - 40,
    540,
    125,
    35,
    35
  )


  val roof =
    new java.awt.Polygon()

  roof.addPoint(
    cx - 180,
    cy - 40
  )

  roof.addPoint(
    cx - 100,
    cy - 150
  )

  roof.addPoint(
    cx + 110,
    cy - 150
  )

  roof.addPoint(
    cx + 185,
    cy - 40
  )


  g.fillPolygon(
    roof
  )


  g.setColor(
    new Color(
      125,
      215,
      245
    )
  )


  g.fillPolygon(
    new java.awt.Polygon(
      Array(
        cx - 145,
        cx - 85,
        cx - 10,
        cx - 10
      ),
      Array(
        cy - 44,
        cy - 125,
        cy - 125,
        cy - 44
      ),
      4
    )
  )


  g.fillPolygon(
    new java.awt.Polygon(
      Array(
        cx + 10,
        cx + 10,
        cx + 115,
        cx + 150
      ),
      Array(
        cy - 44,
        cy - 125,
        cy - 125,
        cy - 44
      ),
      4
    )
  )


  g.setColor(
    Color.BLACK
  )


  g.fillOval(
    cx - 210,
    cy + 35,
    95,
    95
  )


  g.fillOval(
    cx + 115,
    cy + 35,
    95,
    95
  )


  g.setColor(
    Color.LIGHT_GRAY
  )


  g.fillOval(
    cx - 178,
    cy + 67,
    32,
    32
  )


  g.fillOval(
    cx + 147,
    cy + 67,
    32,
    32
  )


  g.setColor(
    Color.YELLOW
  )


  g.fillOval(
    cx - 258,
    cy - 12,
    30,
    27
  )


  g.fillOval(
    cx + 228,
    cy - 12,
    30,
    27
  )


  g.setColor(
    new Color(
      35,
      35,
      40
    )
  )


  g.setStroke(
    new BasicStroke(
      6
    )
  )


  g.drawRoundRect(
    cx - 270,
    cy - 40,
    540,
    125,
    35,
    35
  )


  g.dispose()

  canvas.repaint()
}


// ============================================================
//                    HOUSE
// ============================================================

def drawHouse(): Unit = {

  clearImage()

  val g =
    drawingGraphics

  val cx =
    CENTER_X


  g.setColor(
    new Color(
      245,
      205,
      125
    )
  )


  g.fillRect(
    cx - 205,
    230,
    410,
    260
  )


  val roof =
    new java.awt.Polygon()


  roof.addPoint(
    cx - 260,
    230
  )

  roof.addPoint(
    cx,
    45
  )

  roof.addPoint(
    cx + 260,
    230
  )


  g.setColor(
    new Color(
      180,
      55,
      45
    )
  )


  g.fillPolygon(
    roof
  )


  g.setColor(
    new Color(
      125,
      78,
      45
    )
  )


  g.fillRect(
    cx - 50,
    340,
    100,
    150
  )


  g.setColor(
    new Color(
      85,
      190,
      240
    )
  )


  g.fillRect(
    cx - 160,
    275,
    75,
    75
  )


  g.fillRect(
    cx + 85,
    275,
    75,
    75
  )


  g.setColor(
    new Color(
      70,
      165,
      75
    )
  )


  g.fillRect(
    0,
    490,
    CANVAS_WIDTH,
    110
  )


  g.setColor(
    Color.YELLOW
  )


  g.fillOval(
    70,
    50,
    105,
    105
  )


  g.dispose()

  canvas.repaint()
}


// ============================================================
//                     TREE
// ============================================================

def drawTree(): Unit = {

  clearImage()

  val g =
    drawingGraphics

  val cx =
    CENTER_X


  g.setColor(
    new Color(
      70,
      165,
      75
    )
  )


  g.fillRect(
    0,
    490,
    CANVAS_WIDTH,
    110
  )


  g.setColor(
    new Color(
      135,
      82,
      45
    )
  )


  g.fillRoundRect(
    cx - 45,
    280,
    90,
    215,
    25,
    25
  )


  g.setColor(
    new Color(
      40,
      170,
      70
    )
  )


  g.fillOval(
    cx - 190,
    115,
    225,
    190
  )


  g.fillOval(
    cx - 15,
    85,
    230,
    215
  )


  g.fillOval(
    cx - 105,
    35,
    230,
    215
  )


  g.dispose()

  canvas.repaint()
}


// ============================================================
//                      PERSON
// ============================================================

def drawPerson(): Unit = {

  clearImage()

  val g =
    drawingGraphics

  val cx =
    CENTER_X

  val headY =
    100


  g.setColor(
    new Color(
      245,
      190,
      145
    )
  )


  g.fillOval(
    cx - 70,
    headY,
    140,
    150
  )


  g.setColor(
    new Color(
      50,
      35,
      25
    )
  )


  g.fillArc(
    cx - 73,
    headY - 20,
    146,
    95,
    0,
    180
  )


  g.setColor(
    Color.BLACK
  )


  g.fillOval(
    cx - 38,
    headY + 55,
    13,
    13
  )


  g.fillOval(
    cx + 25,
    headY + 55,
    13,
    13
  )


  g.setColor(
    new Color(
      55,
      125,
      215
    )
  )


  g.fillRoundRect(
    cx - 100,
    headY + 145,
    200,
    180,
    30,
    30
  )


  g.setColor(
    new Color(
      245,
      190,
      145
    )
  )


  g.setStroke(
    new BasicStroke(
      27,
      BasicStroke.CAP_ROUND,
      BasicStroke.JOIN_ROUND
    )
  )


  g.drawLine(
    cx - 85,
    headY + 180,
    cx - 175,
    headY + 300
  )


  g.drawLine(
    cx + 85,
    headY + 180,
    cx + 175,
    headY + 300
  )


  g.setColor(
    new Color(
      45,
      45,
      55
    )
  )


  g.setStroke(
    new BasicStroke(
      40,
      BasicStroke.CAP_ROUND,
      BasicStroke.JOIN_ROUND
    )
  )


  g.drawLine(
    cx - 45,
    headY + 305,
    cx - 60,
    headY + 455
  )


  g.drawLine(
    cx + 45,
    headY + 305,
    cx + 60,
    headY + 455
  )


  g.dispose()

  canvas.repaint()
}


// ============================================================
//                       ROBOT
// ============================================================

def drawRobot(): Unit = {

  clearImage()

  val g =
    drawingGraphics

  val cx =
    CENTER_X

  val cy =
    CENTER_Y


  g.setColor(
    new Color(
      105,
      160,
      195
    )
  )


  g.fillRoundRect(
    cx - 150,
    cy - 10,
    300,
    215,
    35,
    35
  )


  g.setColor(
    new Color(
      160,
      195,
      215
    )
  )


  g.fillRoundRect(
    cx - 175,
    cy - 190,
    350,
    170,
    40,
    40
  )


  g.setColor(
    Color.CYAN
  )


  g.fillOval(
    cx - 105,
    cy - 140,
    60,
    60
  )


  g.fillOval(
    cx + 45,
    cy - 140,
    60,
    60
  )


  g.setColor(
    Color.DARK_GRAY
  )


  g.fillRoundRect(
    cx - 85,
    cy - 65,
    170,
    35,
    15,
    15
  )


  g.setStroke(
    new BasicStroke(
      9
    )
  )


  g.drawLine(
    cx,
    cy - 190,
    cx,
    cy - 255
  )


  g.setColor(
    Color.RED
  )


  g.fillOval(
    cx - 20,
    cy - 275,
    40,
    40
  )


  g.dispose()

  canvas.repaint()
}


// ============================================================
//                        CAT
// ============================================================

def drawCat(): Unit = {

  clearImage()

  val g =
    drawingGraphics

  val cx =
    CENTER_X

  val cy =
    CENTER_Y


  g.setColor(
    new Color(
      180,
      180,
      190
    )
  )


  g.fillOval(
    cx - 140,
    cy - 5,
    280,
    220
  )


  g.fillOval(
    cx - 130,
    cy - 160,
    260,
    210
  )


  val ear1 =
    new java.awt.Polygon()


  ear1.addPoint(
    cx - 110,
    cy - 120
  )

  ear1.addPoint(
    cx - 75,
    cy - 220
  )

  ear1.addPoint(
    cx - 25,
    cy - 140
  )


  val ear2 =
    new java.awt.Polygon()


  ear2.addPoint(
    cx + 110,
    cy - 120
  )

  ear2.addPoint(
    cx + 75,
    cy - 220
  )

  ear2.addPoint(
    cx + 25,
    cy - 140
  )


  g.fillPolygon(
    ear1
  )

  g.fillPolygon(
    ear2
  )


  g.setColor(
    new Color(
      70,
      185,
      95
    )
  )


  g.fillOval(
    cx - 75,
    cy - 85,
    45,
    45
  )

  g.fillOval(
    cx + 30,
    cy - 85,
    45,
    45
  )


  g.setColor(
    Color.PINK
  )


  g.fillOval(
    cx - 12,
    cy - 25,
    24,
    18
  )


  g.dispose()

  canvas.repaint()
}


// ============================================================
//                       DOG
// ============================================================

def drawDog(): Unit = {

  clearImage()

  val g =
    drawingGraphics

  val cx =
    CENTER_X

  val cy =
    CENTER_Y


  g.setColor(
    new Color(
      180,
      120,
      70
    )
  )


  g.fillOval(
    cx - 160,
    cy - 20,
    320,
    205
  )


  g.fillOval(
    cx - 135,
    cy - 170,
    270,
    230
  )


  g.setColor(
    new Color(
      120,
      75,
      45
    )
  )


  g.fillOval(
    cx - 170,
    cy - 120,
    75,
    150
  )


  g.fillOval(
    cx + 95,
    cy - 120,
    75,
    150
  )


  g.setColor(
    Color.BLACK
  )


  g.fillOval(
    cx - 70,
    cy - 85,
    22,
    25
  )


  g.fillOval(
    cx + 48,
    cy - 85,
    22,
    25
  )


  g.fillOval(
    cx - 22,
    cy - 35,
    44,
    32
  )


  g.dispose()

  canvas.repaint()
}


// ============================================================
//                       BIRD
// ============================================================

def drawBird(): Unit = {

  clearImage()

  val g =
    drawingGraphics


  g.setPaint(
    new GradientPaint(
      0,
      0,
      new Color(
        120,
        215,
        255
      ),
      0,
      CANVAS_HEIGHT,
      Color.WHITE
    )
  )


  g.fillRect(
    0,
    0,
    CANVAS_WIDTH,
    CANVAS_HEIGHT
  )


  val cx =
    CENTER_X

  val cy =
    CENTER_Y


  g.setColor(
    new Color(
      65,
      130,
      225
    )
  )


  g.fillOval(
    cx - 145,
    cy - 95,
    285,
    185
  )


  g.fillOval(
    cx + 60,
    cy - 145,
    135,
    130
  )


  g.setColor(
    Color.BLACK
  )


  g.fillOval(
    cx + 140,
    cy - 105,
    18,
    18
  )


  g.setColor(
    Color.ORANGE
  )


  val beak =
    new java.awt.Polygon()


  beak.addPoint(
    cx + 195,
    cy - 80
  )

  beak.addPoint(
    cx + 260,
    cy - 55
  )

  beak.addPoint(
    cx + 195,
    cy - 35
  )


  g.fillPolygon(
    beak
  )


  g.dispose()

  canvas.repaint()
}


// ============================================================
//                      FLOWER
// ============================================================

def drawFlower(): Unit = {

  clearImage()

  val g =
    drawingGraphics

  val cx =
    CENTER_X

  val cy =
    230


  g.setColor(
    new Color(
      45,
      155,
      60
    )
  )


  g.setStroke(
    new BasicStroke(
      15
    )
  )


  g.drawLine(
    cx,
    cy + 55,
    cx,
    510
  )


  val colors =
    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 angle =
      i * math.Pi / 3.0


    val px =
      cx +
      (math.cos(angle) * 80).toInt -
      50


    val py =
      cy +
      (math.sin(angle) * 80).toInt -
      50


    g.setColor(
      colors(i)
    )


    g.fillOval(
      px,
      py,
      100,
      100
    )


    i += 1
  }


  g.setColor(
    Color.YELLOW
  )


  g.fillOval(
    cx - 50,
    cy - 50,
    100,
    100
  )


  g.dispose()

  canvas.repaint()
}


// ============================================================
//                       STAR
// ============================================================

def drawStar(): Unit = {

  clearImage()

  val g =
    drawingGraphics


  val star =
    new java.awt.Polygon()


  var i =
    0


  while (
    i < 10
  ) {

    val angle =
      -math.Pi / 2 +
      i * math.Pi / 5.0


    val radius =
      if (
        i % 2 == 0
      ) {
        190.0
      } else {
        80.0
      }


    star.addPoint(
      CENTER_X +
      (math.cos(angle) * radius).toInt,
      CENTER_Y +
      (math.sin(angle) * radius).toInt
    )


    i += 1
  }


  g.setColor(
    new Color(
      255,
      210,
      0
    )
  )


  g.fillPolygon(
    star
  )


  g.dispose()

  canvas.repaint()
}


// ============================================================
//                       HEART
// ============================================================

def drawHeart(): Unit = {

  clearImage()

  val g =
    drawingGraphics


  val path =
    new java.awt.geom.Path2D.Double()


  path.moveTo(
    CENTER_X,
    CENTER_Y + 190
  )


  path.curveTo(
    CENTER_X - 270,
    CENTER_Y + 20,
    CENTER_X - 170,
    CENTER_Y - 175,
    CENTER_X,
    CENTER_Y - 45
  )


  path.curveTo(
    CENTER_X + 170,
    CENTER_Y - 175,
    CENTER_X + 270,
    CENTER_Y + 20,
    CENTER_X,
    CENTER_Y + 190
  )


  g.setColor(
    Color.RED
  )


  g.fill(
    path
  )


  g.dispose()

  canvas.repaint()
}


// ============================================================
//                    GENERIC DRAW
// ============================================================

def drawGeneric(): Unit = {

  clearImage()

  val g =
    drawingGraphics


  g.setColor(
    new Color(
      75,
      135,
      225
    )
  )


  g.fillRoundRect(
    280,
    150,
    440,
    300,
    40,
    40
  )


  g.setColor(
    Color.YELLOW
  )


  g.fillOval(
    430,
    230,
    140,
    140
  )


  g.dispose()

  canvas.repaint()
}


// ============================================================
//                  TEXT TO DRAW
// ============================================================

def drawFromText(
  value: String
): Unit = {

  val text =
    value
      .trim
      .toLowerCase


  if (
    text.length == 0
  ) {

    status.setText(
      "Write something first."
    )


    return
  }


  rememberUndo()


  if (
    text.indexOf("car") >= 0 ||
    text.indexOf("auto") >= 0 ||
    text.indexOf("taxi") >= 0 ||
    text.indexOf("bus") >= 0 ||
    text.indexOf("truck") >= 0 ||
    text.indexOf("bike") >= 0
  ) {

    drawCar()

  } else if (
    text.indexOf("house") >= 0 ||
    text.indexOf("home") >= 0 ||
    text.indexOf("building") >= 0 ||
    text.indexOf("school") >= 0
  ) {

    drawHouse()

  } else if (
    text.indexOf("tree") >= 0 ||
    text.indexOf("forest") >= 0 ||
    text.indexOf("plant") >= 0
  ) {

    drawTree()

  } else if (
    text.indexOf("boy") >= 0 ||
    text.indexOf("girl") >= 0 ||
    text.indexOf("man") >= 0 ||
    text.indexOf("woman") >= 0 ||
    text.indexOf("person") >= 0 ||
    text.indexOf("human") >= 0 ||
    text.indexOf("child") >= 0 ||
    text.indexOf("baby") >= 0 ||
    text.indexOf("doctor") >= 0 ||
    text.indexOf("teacher") >= 0
  ) {

    drawPerson()

  } else if (
    text.indexOf("robot") >= 0
  ) {

    drawRobot()

  } else if (
    text.indexOf("cat") >= 0 ||
    text.indexOf("kitten") >= 0
  ) {

    drawCat()

  } else if (
    text.indexOf("dog") >= 0 ||
    text.indexOf("puppy") >= 0
  ) {

    drawDog()

  } else if (
    text.indexOf("bird") >= 0 ||
    text.indexOf("eagle") >= 0 ||
    text.indexOf("parrot") >= 0
  ) {

    drawBird()

  } else if (
    text.indexOf("flower") >= 0 ||
    text.indexOf("rose") >= 0
  ) {

    drawFlower()

  } else if (
    text.indexOf("star") >= 0
  ) {

    drawStar()

  } else if (
    text.indexOf("heart") >= 0
  ) {

    drawHeart()

  } else if (
    text.indexOf("pizza") >= 0 ||
    text.indexOf("burger") >= 0 ||
    text.indexOf("cake") >= 0
  ) {

    drawFood()

  } else if (
    text.indexOf("fish") >= 0 ||
    text.indexOf("shark") >= 0 ||
    text.indexOf("whale") >= 0
  ) {

    drawFish()

  } else if (
    text.indexOf("planet") >= 0 ||
    text.indexOf("earth") >= 0 ||
    text.indexOf("mars") >= 0 ||
    text.indexOf("moon") >= 0 ||
    text.indexOf("galaxy") >= 0
  ) {

    drawSpace()

  } else {

    drawGeneric()
  }


  status.setText(
    "Created: " +
    value
  )


  canvas.repaint()
}


// ============================================================
//                      FOOD
// ============================================================

def drawFood(): Unit = {

  clearImage()

  val g =
    drawingGraphics


  g.setColor(
    new Color(
      240,
      175,
      50
    )
  )


  g.fillOval(
    CENTER_X - 190,
    CENTER_Y - 100,
    380,
    200
  )


  g.setColor(
    Color.RED
  )


  g.fillOval(
    CENTER_X - 120,
    CENTER_Y - 10,
    38,
    38
  )


  g.fillOval(
    CENTER_X + 45,
    CENTER_Y - 25,
    38,
    38
  )


  g.dispose()

  canvas.repaint()
}


// ============================================================
//                       FISH
// ============================================================

def drawFish(): Unit = {

  clearImage()

  val g =
    drawingGraphics


  g.setColor(
    new Color(
      70,
      155,
      230
    )
  )


  g.fillOval(
    CENTER_X - 175,
    CENTER_Y - 90,
    350,
    180
  )


  val tail =
    new java.awt.Polygon()


  tail.addPoint(
    CENTER_X + 150,
    CENTER_Y
  )


  tail.addPoint(
    CENTER_X + 260,
    CENTER_Y - 90
  )


  tail.addPoint(
    CENTER_X + 260,
    CENTER_Y + 90
  )


  g.fillPolygon(
    tail
  )


  g.setColor(
    Color.BLACK
  )


  g.fillOval(
    CENTER_X - 100,
    CENTER_Y - 35,
    22,
    22
  )


  g.dispose()

  canvas.repaint()
}


// ============================================================
//                       SPACE
// ============================================================

def drawSpace(): Unit = {

  clearImage()

  val g =
    drawingGraphics


  g.setColor(
    new Color(
      5,
      10,
      35
    )
  )


  g.fillRect(
    0,
    0,
    CANVAS_WIDTH,
    CANVAS_HEIGHT
  )


  g.setColor(
    Color.WHITE
  )


  var i =
    0


  while (
    i < 75
  ) {

    val x =
      (i * 73) % CANVAS_WIDTH


    val y =
      (i * 43) % 400


    g.fillOval(
      x,
      y,
      4,
      4
    )


    i += 1
  }


  g.setColor(
    new Color(
      90,
      150,
      240
    )
  )


  g.fillOval(
    CENTER_X - 120,
    CENTER_Y - 120,
    240,
    240
  )


  g.dispose()

  canvas.repaint()
}


// ============================================================
//                 BACKGROUND LIST
// ============================================================

val backgroundList =
  Array(
    "SKY",
    "SUNNY DAY",
    "SUNRISE",
    "SUNSET",
    "GOLDEN SUNSET",
    "NIGHT",
    "NIGHT SKY",
    "STAR NIGHT",
    "SPACE",
    "GALAXY",
    "DEEP SPACE",
    "COSMIC",
    "OCEAN",
    "DEEP OCEAN",
    "UNDERWATER",
    "BLUE OCEAN",
    "BEACH",
    "TROPICAL BEACH",
    "ISLAND",
    "PARADISE",
    "FOREST",
    "DEEP FOREST",
    "GREEN VALLEY",
    "MOUNTAIN",
    "SNOW",
    "SNOW WORLD",
    "ICE",
    "DESERT",
    "RAINBOW",
    "CLOUD WORLD",
    "CITY",
    "CITY NIGHT",
    "NEON CITY",
    "FUTURE CITY",
    "CYBER CITY",
    "MAGIC",
    "MAGICAL WORLD",
    "FANTASY",
    "FAIRY WORLD",
    "CARTOON WORLD",
    "COMIC WORLD",
    "CANDY WORLD",
    "PINK DREAM",
    "BLUE DREAM",
    "PURPLE DREAM",
    "GOLDEN WORLD",
    "ROYAL WORLD",
    "FIRE WORLD",
    "VOLCANO",
    "AUTUMN",
    "SPRING",
    "SUMMER",
    "WINTER",
    "JUNGLE",
    "DREAM WORLD"
  )


// ============================================================
//               BACKGROUND COLOR SELECTOR
// ============================================================

def getThemeColors(
  theme: String
): Array[Color] = {

  val t =
    theme.toUpperCase


  if (
    t.indexOf("SUNSET") >= 0
  ) {

    Array(
      new Color(255,120,80),
      new Color(105,55,155)
    )

  } else if (
    t.indexOf("SUNRISE") >= 0
  ) {

    Array(
      new Color(255,180,105),
      new Color(255,230,155)
    )

  } else if (
    t.indexOf("NIGHT") >= 0
  ) {

    Array(
      new Color(10,18,65),
      new Color(60,45,115)
    )

  } else if (
    t.indexOf("SPACE") >= 0 ||
    t.indexOf("GALAXY") >= 0 ||
    t.indexOf("COSMIC") >= 0
  ) {

    Array(
      new Color(3,5,25),
      new Color(60,10,100)
    )

  } else if (
    t.indexOf("OCEAN") >= 0 ||
    t.indexOf("UNDERWATER") >= 0
  ) {

    Array(
      new Color(100,220,255),
      new Color(10,80,180)
    )

  } else if (
    t.indexOf("BEACH") >= 0 ||
    t.indexOf("ISLAND") >= 0 ||
    t.indexOf("PARADISE") >= 0
  ) {

    Array(
      new Color(100,220,255),
      new Color(245,205,125)
    )

  } else if (
    t.indexOf("FOREST") >= 0 ||
    t.indexOf("JUNGLE") >= 0 ||
    t.indexOf("GREEN") >= 0
  ) {

    Array(
      new Color(175,235,205),
      new Color(50,145,70)
    )

  } else if (
    t.indexOf("MOUNTAIN") >= 0
  ) {

    Array(
      new Color(175,220,255),
      new Color(105,130,160)
    )

  } else if (
    t.indexOf("SNOW") >= 0 ||
    t.indexOf("ICE") >= 0
  ) {

    Array(
      Color.WHITE,
      new Color(145,215,250)
    )

  } else if (
    t.indexOf("DESERT") >= 0 ||
    t.indexOf("AUTUMN") >= 0
  ) {

    Array(
      new Color(255,220,150),
      new Color(205,145,80)
    )

  } else if (
    t.indexOf("CITY") >= 0 ||
    t.indexOf("FUTURE") >= 0 ||
    t.indexOf("CYBER") >= 0
  ) {

    Array(
      new Color(125,150,190),
      new Color(40,50,70)
    )

  } else if (
    t.indexOf("NEON") >= 0
  ) {

    Array(
      new Color(8,15,55),
      new Color(105,0,145)
    )

  } else if (
    t.indexOf("MAGIC") >= 0 ||
    t.indexOf("FANTASY") >= 0 ||
    t.indexOf("FAIRY") >= 0
  ) {

    Array(
      new Color(215,185,255),
      new Color(105,55,165)
    )

  } else if (
    t.indexOf("CANDY") >= 0 ||
    t.indexOf("PINK") >= 0
  ) {

    Array(
      new Color(255,195,225),
      new Color(245,95,175)
    )

  } else if (
    t.indexOf("GOLD") >= 0 ||
    t.indexOf("ROYAL") >= 0
  ) {

    Array(
      new Color(255,235,135),
      new Color(205,145,35)
    )

  } else if (
    t.indexOf("FIRE") >= 0 ||
    t.indexOf("VOLCANO") >= 0
  ) {

    Array(
      new Color(255,150,70),
      new Color(180,35,35)
    )

  } else if (
    t.indexOf("PURPLE") >= 0
  ) {

    Array(
      new Color(220,190,255),
      new Color(105,45,170)
    )

  } else if (
    t.indexOf("BLUE") >= 0
  ) {

    Array(
      new Color(185,230,255),
      new Color(60,125,225)
    )

  } else {

    Array(
      new Color(165,220,255),
      new Color(95,180,100)
    )
  }
}


// ============================================================
//                CREATE BACKGROUND
// ============================================================

def createBackground(
  theme: String
): BufferedImage = {

  val result =
    new BufferedImage(
      CANVAS_WIDTH,
      CANVAS_HEIGHT,
      BufferedImage.TYPE_INT_RGB
    )


  val g =
    result.createGraphics()


  val colors =
    getThemeColors(
      theme
    )


  g.setPaint(
    new GradientPaint(
      0,
      0,
      colors(0),
      0,
      CANVAS_HEIGHT,
      colors(1)
    )
  )


  g.fillRect(
    0,
    0,
    CANVAS_WIDTH,
    CANVAS_HEIGHT
  )


  val t =
    theme.toUpperCase


  if (
    t.indexOf("NIGHT") < 0 &&
    t.indexOf("SPACE") < 0 &&
    t.indexOf("GALAXY") < 0 &&
    t.indexOf("NEON") < 0
  ) {

    g.setColor(
      new Color(
        255,
        255,
        255,
        120
      )
    )


    g.fillOval(
      60,
      55,
      150,
      50
    )


    g.fillOval(
      105,
      30,
      105,
      70
    )


    g.fillOval(
      700,
      80,
      150,
      50
    )


    g.fillOval(
      750,
      55,
      105,
      70
    )
  }


  if (
    t == "SKY" ||
    t.indexOf("SUN") >= 0 ||
    t.indexOf("BEACH") >= 0
  ) {

    g.setColor(
      new Color(
        255,
        210,
        55
      )
    )


    g.fillOval(
      830,
      45,
      105,
      105
    )
  }


  if (
    t.indexOf("NIGHT") >= 0 ||
    t.indexOf("SPACE") >= 0 ||
    t.indexOf("GALAXY") >= 0 ||
    t.indexOf("MAGIC") >= 0 ||
    t.indexOf("FANTASY") >= 0
  ) {

    g.setColor(
      Color.WHITE
    )


    var i =
      0


    while (
      i < 100
    ) {

      val sx =
        (i * 71) % CANVAS_WIDTH


      val sy =
        (i * 43) % 370


      g.fillOval(
        sx,
        sy,
        3 + (i % 4),
        3 + (i % 4)
      )


      i += 1
    }
  }


  if (
    t.indexOf("RAINBOW") >= 0
  ) {

    val rainbow =
      Array(
        Color.RED,
        Color.ORANGE,
        Color.YELLOW,
        Color.GREEN,
        Color.CYAN,
        Color.BLUE,
        Color.MAGENTA
      )


    var r =
      0


    while (
      r < rainbow.length
    ) {

      g.setColor(
        rainbow(r)
      )


      g.setStroke(
        new BasicStroke(
          9
        )
      )


      g.drawArc(
        220,
        125 + r * 9,
        560 - r * 18,
        350 - r * 18,
        0,
        180
      )


      r += 1
    }
  }


  if (
    t.indexOf("SPACE") < 0 &&
    t.indexOf("GALAXY") < 0 &&
    t.indexOf("NIGHT") < 0 &&
    t.indexOf("NEON") < 0
  ) {

    if (
      t.indexOf("OCEAN") >= 0 ||
      t.indexOf("UNDERWATER") >= 0
    ) {

      g.setColor(
        new Color(
          20,
          120,
          190,
          190
        )
      )

    } else {

      g.setColor(
        new Color(
          70,
          165,
          75,
          175
        )
      )
    }


    g.fillRect(
      0,
      490,
      CANVAS_WIDTH,
      110
    )
  }


  if (
    t.indexOf("CITY") >= 0 ||
    t.indexOf("FUTURE") >= 0 ||
    t.indexOf("CYBER") >= 0
  ) {

    var b =
      0


    while (
      b < 10
    ) {

      val bx =
        b * 105


      val bh =
        120 +
        (b % 4) * 50


      g.setColor(
        new Color(
          35,
          45,
          65,
          235
        )
      )


      g.fillRect(
        bx,
        490 - bh,
        80,
        bh
      )


      g.setColor(
        if (
          t.indexOf("NEON") >= 0
        ) {
          Color.CYAN
        } else {
          Color.YELLOW
        }
      )


      var wy =
        490 - bh + 20


      while (
        wy < 480
      ) {

        g.fillRect(
          bx + 15,
          wy,
          12,
          18
        )


        wy += 35
      }


      b += 1
    }
  }


  g.dispose()


  result
}


// ============================================================
//             REMOVE WHITE BACKGROUND OF SKETCH
// ============================================================

def isWhitePixel(
  rgb: Int
): Boolean = {

  val red =
    (rgb >> 16) & 255

  val green =
    (rgb >> 8) & 255

  val blue =
    rgb & 255


  red >= 245 &&
  green >= 245 &&
  blue >= 245
}


// ============================================================
//                  COMPOSITE DRAWING
// ============================================================

def composeDrawing(
  background: BufferedImage
): BufferedImage = {

  val result =
    copyImage(
      background
    )


  var x =
    0


  while (
    x < CANVAS_WIDTH
  ) {

    var y =
      0


    while (
      y < CANVAS_HEIGHT
    ) {

      val rgb =
        drawingImage.getRGB(
          x,
          y
        )


      if (
        !isWhitePixel(
          rgb
        )
      ) {

        result.setRGB(
          x,
          y,
          rgb
        )
      }


      y += 1
    }


    x += 1
  }


  result
}


// ============================================================
//                     APPLY STYLE
// ============================================================

def applyStyle(
  theme: String,
  style: String
): BufferedImage = {

  val background =
    createBackground(
      theme
    )


  val base =
    composeDrawing(
      background
    )


  val result =
    copyImage(
      base
    )


  val g =
    result.createGraphics()


  if (
    style == "3D"
  ) {

    var d =
      20


    while (
      d > 0
    ) {

      g.setColor(
        new Color(
          0,
          0,
          0,
          10
        )
      )


      g.drawImage(
        base,
        d,
        d,
        null
      )


      d -= 1
    }


    g.drawImage(
      base,
      0,
      0,
      null
    )
  }


  if (
    style == "GLOSSY"
  ) {

    g.setColor(
      new Color(
        255,
        255,
        255,
        50
      )
    )


    g.fillRoundRect(
      20,
      20,
      960,
      130,
      35,
      35
    )
  }


  if (
    style == "NEON"
  ) {

    g.setColor(
      new Color(
        0,
        255,
        255,
        100
      )
    )


    g.setStroke(
      new BasicStroke(
        12
      )
    )


    g.drawRoundRect(
      10,
      10,
      980,
      580,
      30,
      30
    )


    g.setColor(
      new Color(
        255,
        0,
        255,
        110
      )
    )


    g.setStroke(
      new BasicStroke(
        4
      )
    )


    g.drawRoundRect(
      20,
      20,
      960,
      560,
      25,
      25
    )
  }


  if (
    style == "SOFT"
  ) {

    g.setColor(
      new Color(
        255,
        255,
        255,
        35
      )
    )


    g.fillRect(
      0,
      0,
      CANVAS_WIDTH,
      CANVAS_HEIGHT
    )
  }


  if (
    style == "COMIC"
  ) {

    g.setColor(
      new Color(
        10,
        10,
        10,
        150
      )
    )


    g.setStroke(
      new BasicStroke(
        8
      )
    )


    g.drawRoundRect(
      8,
      8,
      984,
      584,
      25,
      25
    )
  }


  if (
    style == "MAGIC"
  ) {

    g.setColor(
      Color.WHITE
    )


    var m =
      0


    while (
      m < 45
    ) {

      val px =
        (m * 83) % CANVAS_WIDTH


      val py =
        (m * 47) % CANVAS_HEIGHT


      g.fillOval(
        px,
        py,
        5,
        5
      )


      m += 1
    }
  }


  if (
    style == "GOLD"
  ) {

    g.setColor(
      new Color(
        255,
        215,
        70,
        100
      )
    )


    g.setStroke(
      new BasicStroke(
        10
      )
    )


    g.drawRoundRect(
      12,
      12,
      976,
      576,
      30,
      30
    )
  }


  g.dispose()


  result
}


// ============================================================
//                    COLORIZE DIALOG
// ============================================================

def openColorizeDialog(): Unit = {

  val backgroundBox =
    new JComboBox[String](
      backgroundList
    )


  backgroundBox.setSelectedItem(
    currentTheme
  )


  val styleChoice =
    new JComboBox[String](
      Array(
        "3D",
        "GLOSSY",
        "NEON",
        "SOFT",
        "COMIC",
        "MAGIC",
        "GOLD"
      )
    )


  styleChoice.setSelectedItem(
    currentStyle
  )


  val panel =
    new JPanel(
      new BorderLayout(
        10,
        10
      )
    )


  val controls =
    new JPanel(
      new FlowLayout(
        FlowLayout.LEFT
      )
    )


  controls.add(
    new JLabel(
      "BACKGROUND:"
    )
  )


  controls.add(
    backgroundBox
  )


  controls.add(
    new JLabel(
      "STYLE:"
    )
  )


  controls.add(
    styleChoice
  )


  panel.add(
    new JLabel(
      "ULTRA COLORIZE"
    ),
    BorderLayout.NORTH
  )


  panel.add(
    controls,
    BorderLayout.CENTER
  )


  val answer =
    JOptionPane.showConfirmDialog(
      frame,
      panel,
      "COLORIZE DRAWING",
      JOptionPane.OK_CANCEL_OPTION,
      JOptionPane.PLAIN_MESSAGE
    )


  if (
    answer ==
    JOptionPane.OK_OPTION
  ) {

    rememberUndo()


    currentTheme =
      backgroundBox
        .getSelectedItem
        .toString


    currentStyle =
      styleChoice
        .getSelectedItem
        .toString


    val result =
      applyStyle(
        currentTheme,
        currentStyle
      )


    restoreImage(
      result
    )


    canvas.repaint()


    status.setText(
      "Colorize complete: " +
      currentTheme
    )
  }
}


// ============================================================
//                    3D PREVIEW
// ============================================================

def show3DPreview(): Unit = {

  val image =
    applyStyle(
      currentTheme,
      "3D"
    )


  val previewFrame =
    new JFrame(
      "ULTRA 3D PREVIEW"
    )


  previewFrame.setDefaultCloseOperation(
    WindowConstants.DISPOSE_ON_CLOSE
  )


  previewFrame.setSize(
    1100,
    760
  )


  previewFrame.setLocationRelativeTo(
    frame
  )


  val previewPanel =
    new JPanel {

      override def paintComponent(
        graphics: Graphics
      ): Unit = {

        super.paintComponent(
          graphics
        )


        val g =
          graphics.asInstanceOf[
            Graphics2D
          ]


        g.setRenderingHint(
          RenderingHints.KEY_INTERPOLATION,
          RenderingHints.VALUE_INTERPOLATION_BICUBIC
        )


        val availableWidth =
          getWidth - 40


        val availableHeight =
          getHeight - 70


        val scale =
          math.min(
            availableWidth.toDouble /
              image.getWidth,
            availableHeight.toDouble /
              image.getHeight
          )


        val imageWidth =
          math.max(
            1,
            (image.getWidth * scale).toInt
          )


        val imageHeight =
          math.max(
            1,
            (image.getHeight * scale).toInt
          )


        val x =
          (getWidth - imageWidth) / 2


        val y =
          (getHeight - imageHeight) / 2


        g.drawImage(
          image,
          x,
          y,
          imageWidth,
          imageHeight,
          null
        )
      }
    }


  val animateButton =
    new JButton(
      "ANIMATE"
    )


  val stopButton =
    new JButton(
      "STOP"
    )


  val saveButton =
    new JButton(
      "SAVE 3D"
    )


  animateButton.setFocusable(
    false
  )


  stopButton.setFocusable(
    false
  )


  saveButton.setFocusable(
    false
  )


  val animationTimer =
    new Timer(
      60,
      new ActionListener {

        override def actionPerformed(
          e: ActionEvent
        ): Unit = {

          if (
            animationEnabled
          ) {

            animationOffset =
              animationOffset + 1

            previewPanel.repaint()
          }
        }
      }
    )


  var previewAnimation =
    false


  animateButton.addActionListener(
    new ActionListener {

      override def actionPerformed(
        e: ActionEvent
      ): Unit = {

        previewAnimation =
          true

        animationEnabled =
          true

        animationTimer.start()
      }
    }
  )


  stopButton.addActionListener(
    new ActionListener {

      override def actionPerformed(
        e: ActionEvent
      ): Unit = {

        previewAnimation =
          false

        animationEnabled =
          false

        animationTimer.stop()
      }
    }
  )


  saveButton.addActionListener(
    new ActionListener {

      override def actionPerformed(
        e: ActionEvent
      ): Unit = {

        saveImageObject(
          image,
          previewFrame
        )
      }
    }
  )


  previewFrame.setLayout(
    new BorderLayout()
  )


  previewFrame.add(
    previewPanel,
    BorderLayout.CENTER
  )


  val buttons =
    new JPanel(
      new FlowLayout(
        FlowLayout.CENTER
      )
    )


  buttons.add(
    animateButton
  )


  buttons.add(
    stopButton
  )


  buttons.add(
    saveButton
  )


  previewFrame.add(
    buttons,
    BorderLayout.SOUTH
  )


  previewFrame.setVisible(
    true
  )
}


// ============================================================
//              ANIMATION STATE
// ============================================================

var animationEnabled =
  false

var animationOffset =
  0


// ============================================================
//                    SAVE IMAGE OBJECT
// ============================================================

def saveImageObject(
  image: BufferedImage,
  owner: JFrame
): Unit = {

  val chooser =
    new JFileChooser()


  if (
    chooser.showSaveDialog(
      owner
    ) ==
    JFileChooser.APPROVE_OPTION
  ) {

    try {

      var file =
        chooser.getSelectedFile


      if (
        !file.getName
          .toLowerCase
          .endsWith(
            ".png"
          )
      ) {

        file =
          new File(
            file.getAbsolutePath +
            ".png"
          )
      }


      ImageIO.write(
        image,
        "png",
        file
      )


      status.setText(
        "Image saved!"
      )

    } catch {

      case ex: Exception =>

        JOptionPane.showMessageDialog(
          owner,
          ex.getMessage,
          "Save Error",
          JOptionPane.ERROR_MESSAGE
        )
    }
  }
}


// ============================================================
//                    SAVE CURRENT
// ============================================================

def saveCurrentImage(): Unit = {

  saveImageObject(
    drawingImage,
    frame
  )
}


// ============================================================
//                     PENCIL
// ============================================================

pencilButton.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      eraserMode =
        false


      status.setText(
        "Pencil selected"
      )
    }
  }
)


// ============================================================
//                      ERASER
// ============================================================

eraserButton.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      eraserMode =
        true


      status.setText(
        "Eraser selected"
      )
    }
  }
)


// ============================================================
//                       SIZE
// ============================================================

sizeBox.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      try {

        brushSize =
          sizeBox
            .getSelectedItem
            .toString
            .toFloat

      } catch {

        case _: Exception =>
      }
    }
  }
)


// ============================================================
//                       DRAW
// ============================================================

drawButton.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      drawFromText(
        writeField.getText
      )
    }
  }
)


writeField.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      drawFromText(
        writeField.getText
      )
    }
  }
)


// ============================================================
//                       COLORIZE
// ============================================================

colorizeButton.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      openColorizeDialog()
    }
  }
)


// ============================================================
//                         3D
// ============================================================

threeDButton.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      show3DPreview()
    }
  }
)


// ============================================================
//                        UNDO
// ============================================================

undoButton.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      if (
        undoImage != null
      ) {

        redoImage =
          copyImage(
            drawingImage
          )


        restoreImage(
          undoImage
        )


        undoImage =
          null


        status.setText(
          "Undo complete"
        )
      }
    }
  }
)


// ============================================================
//                        REDO
// ============================================================

redoButton.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      if (
        redoImage != null
      ) {

        undoImage =
          copyImage(
            drawingImage
          )


        restoreImage(
          redoImage
        )


        redoImage =
          null


        status.setText(
          "Redo complete"
        )
      }
    }
  }
)


// ============================================================
//                        CLEAR
// ============================================================

clearButton.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      rememberUndo()


      clearImage()


      status.setText(
        "Canvas cleared"
      )
    }
  }
)


// ============================================================
//                         SAVE
// ============================================================

saveButton.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      saveCurrentImage()
    }
  }
)


// ============================================================
//                      ZOOM IN
// ============================================================

zoomInButton.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      zoomLevel =
        math.min(
          2.0,
          zoomLevel + 0.10
        )


      canvas.repaint()


      status.setText(
        "Zoom: " +
        math.round(
          zoomLevel * 100
        ) +
        "%"
      )
    }
  }
)


// ============================================================
//                     ZOOM OUT
// ============================================================

zoomOutButton.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      zoomLevel =
        math.max(
          0.60,
          zoomLevel - 0.10
        )


      canvas.repaint()


      status.setText(
        "Zoom: " +
        math.round(
          zoomLevel * 100
        ) +
        "%"
      )
    }
  }
)


// ============================================================
//                       RESET
// ============================================================

resetButton.addActionListener(
  new ActionListener {

    override def actionPerformed(
      e: ActionEvent
    ): Unit = {

      zoomLevel =
        1.0


      currentTheme =
        "SKY"


      currentStyle =
        "3D"


      canvas.repaint()


      status.setText(
        "View reset"
      )
    }
  }
)


// ============================================================
//                    MOUSE DRAWING
// ============================================================

canvas.addMouseListener(
  new MouseAdapter {

    override def mousePressed(
      e: MouseEvent
    ): Unit = {

      rememberUndo()


      isDrawing =
        true


      lastX =
        math.max(
          0,
          math.min(
            CANVAS_WIDTH - 1,
            e.getX
          )
        )


      lastY =
        math.max(
          0,
          math.min(
            CANVAS_HEIGHT - 1,
            e.getY
          )
        )


      if (
        eraserMode
      ) {

        drawingGraphics.setColor(
          Color.WHITE
        )

      } else {

        drawingGraphics.setColor(
          currentColor
        )
      }


      val s =
        math.max(
          1,
          brushSize.toInt
        )


      drawingGraphics.fillOval(
        lastX - s / 2,
        lastY - s / 2,
        s,
        s
      )


      canvas.repaint()
    }


    override def mouseReleased(
      e: MouseEvent
    ): Unit = {

      isDrawing =
        false
    }
  }
)


// ============================================================
//                    MOUSE DRAGGING
// ============================================================

canvas.addMouseMotionListener(
  new MouseMotionAdapter {

    override def mouseDragged(
      e: MouseEvent
    ): Unit = {

      if (
        isDrawing
      ) {

        val x =
          math.max(
            0,
            math.min(
              CANVAS_WIDTH - 1,
              e.getX
            )
          )


        val y =
          math.max(
            0,
            math.min(
              CANVAS_HEIGHT - 1,
              e.getY
            )
          )


        if (
          eraserMode
        ) {

          drawingGraphics.setColor(
            Color.WHITE
          )

        } else {

          drawingGraphics.setColor(
            currentColor
          )
        }


        drawingGraphics.setStroke(
          new BasicStroke(
            brushSize,
            BasicStroke.CAP_ROUND,
            BasicStroke.JOIN_ROUND
          )
        )


        drawingGraphics.drawLine(
          lastX,
          lastY,
          x,
          y
        )


        lastX =
          x


        lastY =
          y


        canvas.repaint()
      }
    }
  }
)


// ============================================================
//                   KEYBOARD SHORTCUTS
// ============================================================

canvas.addKeyListener(
  new KeyAdapter {

    override def keyPressed(
      e: KeyEvent
    ): Unit = {

      if (
        e.isControlDown &&
        e.getKeyCode ==
        KeyEvent.VK_Z
      ) {

        undoButton.doClick()
      }


      if (
        e.isControlDown &&
        e.getKeyCode ==
        KeyEvent.VK_Y
      ) {

        redoButton.doClick()
      }


      if (
        e.getKeyCode ==
        KeyEvent.VK_F2
      ) {

        colorizeButton.doClick()
      }


      if (
        e.getKeyCode ==
        KeyEvent.VK_F3
      ) {

        threeDButton.doClick()
      }
    }
  }
)


// ============================================================
//                    BOTTOM BAR
// ============================================================

val bottom =
  new JPanel(
    new FlowLayout(
      FlowLayout.LEFT,
      8,
      5
    )
  )


bottom.add(
  status
)


bottom.add(
  new JLabel(
    "F2 Colorize | F3 3D | Ctrl+Z Undo | Ctrl+Y Redo"
  )
)


// ============================================================
//                       LAYOUT
// ============================================================

frame.setLayout(
  new BorderLayout()
)


frame.add(
  toolbar,
  BorderLayout.NORTH
)


frame.add(
  canvas,
  BorderLayout.CENTER
)


frame.add(
  bottom,
  BorderLayout.SOUTH
)


// ============================================================
//                        START
// ============================================================

SwingUtilities.invokeLater(
  new Runnable {

    override def run(): Unit = {

      frame.setVisible(
        true
      )


      canvas.requestFocusInWindow()


      frame.requestFocusInWindow()


      status.setText(
        "ULTRA LEGEND READY!"
      )
    }
  }
)