Code Sketch


yoiiigggg
By: Mhalsakant School
Category: Programming
import javax.swing._
import javax.swing.border._
import java.awt._
import java.awt.event._
import java.awt.image.BufferedImage
import java.awt.datatransfer._
import javax.imageio.ImageIO
import java.io._
import java.text.SimpleDateFormat
import java.util.Date
import scala.collection.mutable.ArrayBuffer

// ============================================================
// ULTRA SCALA SWING AI LEARNING STUDIO
// CLEAN / CORRECTED SINGLE FILE VERSION
// ============================================================

// ------------------------------------------------------------
// PASSWORD
// ------------------------------------------------------------

val passwordSecret =
  Array(
    121,97,100,110,101,115,104,
    50,48,49,51
  ).map(_.toChar).mkString

// ------------------------------------------------------------
// GLOBAL STATE
// ------------------------------------------------------------

var speechProcess: Process = null
var savedImage: BufferedImage = null

var currentLesson = 0
var autoNextEnabled = true

var quizIndex = 0
var quizScore = 0

var stopwatchRunning = false
var stopwatchSeconds = 0

var countdownRunning = false
var countdownSeconds = 0

var fontSizeValue = 16

val questionHistory =
  ArrayBuffer[String]()

val activityHistory =
  ArrayBuffer[String]()

// ------------------------------------------------------------
// COLORS
// ------------------------------------------------------------

val BG =
  new Color(17, 19, 27)

val PANEL =
  new Color(27, 30, 41)

val PANEL2 =
  new Color(38, 42, 56)

val PANEL3 =
  new Color(10, 13, 18)

val TEXT =
  new Color(242, 245, 250)

val SUBTEXT =
  new Color(170, 179, 198)

val BLUE =
  new Color(90, 150, 255)

val GREEN =
  new Color(70, 215, 145)

val RED =
  new Color(255, 95, 105)

val YELLOW =
  new Color(255, 205, 75)

// ============================================================
// UI HELPERS
// ============================================================

def makeButton(text: String): JButton = {

  val b =
    new JButton(text)

  b.setFocusPainted(false)
  b.setForeground(TEXT)
  b.setBackground(PANEL2)

  b.setFont(
    new Font(
      "Segoe UI",
      Font.BOLD,
      13
    )
  )

  b.setBorder(
    new CompoundBorder(
      new LineBorder(
        new Color(62, 68, 88)
      ),
      new EmptyBorder(
        8,
        13,
        8,
        13
      )
    )
  )

  b
}

def makeLabel(
    text: String,
    size: Int,
    bold: Boolean
): JLabel = {

  val l =
    new JLabel(text)

  l.setForeground(TEXT)

  l.setFont(
    new Font(
      "Segoe UI",
      if (bold) Font.BOLD else Font.PLAIN,
      size
    )
  )

  l
}

def makeArea(): JTextArea = {

  val a =
    new JTextArea()

  a.setBackground(PANEL3)
  a.setForeground(TEXT)
  a.setCaretColor(TEXT)

  a.setFont(
    new Font(
      "Segoe UI",
      Font.PLAIN,
      fontSizeValue
    )
  )

  a.setLineWrap(true)
  a.setWrapStyleWord(true)

  a.setBorder(
    new EmptyBorder(
      12,
      12,
      12,
      12
    )
  )

  a
}

def makeField(): JTextField = {

  val f =
    new JTextField()

  f.setBackground(PANEL3)
  f.setForeground(TEXT)
  f.setCaretColor(TEXT)

  f.setFont(
    new Font(
      "Segoe UI",
      Font.PLAIN,
      15
    )
  )

  f.setBorder(
    new CompoundBorder(
      new LineBorder(
        new Color(58, 64, 82)
      ),
      new EmptyBorder(
        8,
        10,
        8,
        10
      )
    )
  )

  f
}

def makeScroll(
    c: Component
): JScrollPane = {

  val s =
    new JScrollPane(c)

  s.setBorder(null)

  s.getVerticalScrollBar
    .setUnitIncrement(15)

  s
}

def showInfo(
    title: String,
    message: String
): Unit = {

  JOptionPane.showMessageDialog(
    null,
    message,
    title,
    JOptionPane.INFORMATION_MESSAGE
  )
}

def showWarning(
    title: String,
    message: String
): Unit = {

  JOptionPane.showMessageDialog(
    null,
    message,
    title,
    JOptionPane.WARNING_MESSAGE
  )
}

// ============================================================
// ACTIVITY HISTORY
// ============================================================

def addActivity(
    message: String
): Unit = {

  val stamp =
    new SimpleDateFormat(
      "HH:mm:ss"
    ).format(
      new Date()
    )

  activityHistory +=
    stamp +
    "  " +
    message

  if (
    activityHistory.length > 500
  ) {
    activityHistory.remove(0)
  }
}

// ============================================================
// CLIPBOARD TEXT
// ============================================================

def copyText(
    text: String
): Unit = {

  try {

    val clipboard =
      Toolkit
        .getDefaultToolkit
        .getSystemClipboard

    clipboard.setContents(
      new StringSelection(text),
      null
    )

    addActivity(
      "Text copied"
    )

  } catch {

    case _: Throwable =>

      showWarning(
        "Clipboard",
        "Text copy failed."
      )
  }
}

def pasteText(): String = {

  try {

    val clipboard =
      Toolkit
        .getDefaultToolkit
        .getSystemClipboard

    val transferable =
      clipboard.getContents(null)

    if (
      transferable != null &&
      transferable.isDataFlavorSupported(
        DataFlavor.stringFlavor
      )
    ) {

      transferable
        .getTransferData(
          DataFlavor.stringFlavor
        )
        .toString

    } else {

      ""
    }

  } catch {

    case _: Throwable =>
      ""
  }
}

// ============================================================
// CLIPBOARD IMAGE
// ============================================================

def copyImage(): Unit = {

  if (
    savedImage == null
  ) {

    showWarning(
      "Image",
      "There is no image to copy."
    )

    return
  }

  try {

    val imageForClipboard =
      savedImage

    val transferable =
      new Transferable {

        def getTransferDataFlavors:
            Array[DataFlavor] = {

          Array(
            DataFlavor.imageFlavor
          )
        }

        def isDataFlavorSupported(
            flavor: DataFlavor
        ): Boolean = {

          flavor ==
            DataFlavor.imageFlavor
        }

        def getTransferData(
            flavor: DataFlavor
        ): Object = {

          if (
            flavor ==
              DataFlavor.imageFlavor
          ) {

            imageForClipboard

          } else {

            throw new UnsupportedFlavorException(
              flavor
            )
          }
        }
      }

    Toolkit
      .getDefaultToolkit
      .getSystemClipboard
      .setContents(
        transferable,
        null
      )

    addActivity(
      "Image copied"
    )

  } catch {

    case _: Throwable =>

      showWarning(
        "Image",
        "Image copy failed."
      )
  }
}

def pasteImage(): Boolean = {

  try {

    val clipboard =
      Toolkit
        .getDefaultToolkit
        .getSystemClipboard

    val transferable =
      clipboard.getContents(null)

    if (
      transferable != null &&
      transferable.isDataFlavorSupported(
        DataFlavor.imageFlavor
      )
    ) {

      val obj =
        transferable.getTransferData(
          DataFlavor.imageFlavor
        )

      obj match {

        case bi: BufferedImage =>

          savedImage = bi
          addActivity("Image pasted")
          true

        case img: Image =>

          val width =
            math.max(
              1,
              img.getWidth(null)
            )

          val height =
            math.max(
              1,
              img.getHeight(null)
            )

          val bi =
            new BufferedImage(
              width,
              height,
              BufferedImage.TYPE_INT_ARGB
            )

          val g =
            bi.createGraphics()

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

          g.dispose()

          savedImage = bi

          addActivity(
            "Image pasted"
          )

          true

        case _ =>
          false
      }

    } else {

      false
    }

  } catch {

    case _: Throwable =>
      false
  }
}

// ============================================================
// SPEECH
// ============================================================

def stopSpeech(): Unit = {

  try {

    if (
      speechProcess != null
    ) {

      speechProcess.destroy()

      speechProcess = null
    }

  } catch {

    case _: Throwable =>
  }
}

def speakText(
    text: String
): Unit = {

  stopSpeech()

  try {

    val safe =
      text
        .replace(
          "'",
          "''"
        )
        .replace(
          "\n",
          " "
        )

    val command =
      "Add-Type -AssemblyName System.Speech; " +
      "$s=New-Object System.Speech.Synthesis.SpeechSynthesizer; " +
      "$s.Speak('" +
      safe +
      "');"

    speechProcess =
      new ProcessBuilder(
        "powershell",
        "-NoProfile",
        "-Command",
        command
      ).start()

    addActivity(
      "Teacher voice started"
    )

  } catch {

    case _: Throwable =>
  }
}

// ============================================================
// FILE FUNCTIONS
// ============================================================

def saveTextFile(
    text: String,
    defaultName: String
): Unit = {

  val chooser =
    new JFileChooser()

  chooser.setSelectedFile(
    new File(defaultName)
  )

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

    val writer =
      new FileWriter(
        chooser.getSelectedFile
      )

    try {

      writer.write(text)

    } finally {

      writer.close()
    }

    addActivity(
      "File saved: " +
      chooser.getSelectedFile.getName
    )
  }
}

def loadTextFile(
    area: JTextArea
): Unit = {

  val chooser =
    new JFileChooser()

  if (
    chooser.showOpenDialog(null) ==
      JFileChooser.APPROVE_OPTION
  ) {

    val source =
      scala.io.Source.fromFile(
        chooser.getSelectedFile,
        "UTF-8"
      )

    try {

      area.setText(
        source.mkString
      )

    } finally {

      source.close()
    }

    addActivity(
      "File loaded: " +
      chooser.getSelectedFile.getName
    )
  }
}

// ============================================================
// IMAGE DISPLAY
// ============================================================

def updateImagePreview(
    label: JLabel
): Unit = {

  if (
    savedImage == null
  ) {

    label.setIcon(null)

    label.setText(
      "IMAGE PREVIEW"
    )

    return
  }

  val originalWidth =
    math.max(
      1,
      savedImage.getWidth
    )

  val originalHeight =
    math.max(
      1,
      savedImage.getHeight
    )

  val targetWidth =
    math.max(
      200,
      label.getWidth - 20
    )

  val targetHeight =
    math.max(
      200,
      label.getHeight - 20
    )

  val scale =
    math.min(
      targetWidth.toDouble /
        originalWidth.toDouble,
      targetHeight.toDouble /
        originalHeight.toDouble
    )

  val newWidth =
    math.max(
      1,
      (originalWidth * scale).toInt
    )

  val newHeight =
    math.max(
      1,
      (originalHeight * scale).toInt
    )

  val scaled =
    savedImage.getScaledInstance(
      newWidth,
      newHeight,
      Image.SCALE_SMOOTH
    )

  label.setIcon(
    new ImageIcon(
      scaled
    )
  )

  label.setText("")
}

// ============================================================
// CREATE LOCAL ARTWORK
// ============================================================

def createArtwork(
    prompt: String
): BufferedImage = {

  val width = 900
  val height = 560

  val image =
    new BufferedImage(
      width,
      height,
      BufferedImage.TYPE_INT_ARGB
    )

  val g =
    image.createGraphics()

  g.setPaint(
    new GradientPaint(
      0,
      0,
      new Color(
        15,
        20,
        65
      ),
      width,
      height,
      new Color(
        75,
        15,
        90
      )
    )
  )

  g.fillRect(
    0,
    0,
    width,
    height
  )

  var i = 0

  while (
    i < 55
  ) {

    val x =
      (i * 137) % width

    val y =
      (i * 83) % height

    val r =
      3 + ((i * 7) % 13)

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

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

    i += 1
  }

  g.setColor(
    new Color(
      255,
      220,
      105,
      245
    )
  )

  g.fillOval(
    310,
    95,
    280,
    280
  )

  g.setColor(
    Color.WHITE
  )

  g.setFont(
    new Font(
      "Segoe UI",
      Font.BOLD,
      34
    )
  )

  g.drawString(
    "IMAGE STUDIO",
    40,
    55
  )

  g.setFont(
    new Font(
      "Segoe UI",
      Font.PLAIN,
      18
    )
  )

  val shown =
    if (
      prompt.trim.isEmpty
    )
      "Local generated artwork"
    else
      prompt.trim.take(75)

  g.drawString(
    shown,
    40,
    515
  )

  g.dispose()

  image
}

// ============================================================
// IMAGE FILTERS
// ============================================================

def grayscale(
    source: BufferedImage
): BufferedImage = {

  val result =
    new BufferedImage(
      source.getWidth,
      source.getHeight,
      BufferedImage.TYPE_INT_ARGB
    )

  var x = 0

  while (
    x < source.getWidth
  ) {

    var y = 0

    while (
      y < source.getHeight
    ) {

      val argb =
        source.getRGB(
          x,
          y
        )

      val a =
        (argb >>> 24) & 255

      val r =
        (argb >>> 16) & 255

      val g =
        (argb >>> 8) & 255

      val b =
        argb & 255

      val gray =
        (
          r * 30 +
          g * 59 +
          b * 11
        ) / 100

      val out =
        (a << 24) |
        (gray << 16) |
        (gray << 8) |
        gray

      result.setRGB(
        x,
        y,
        out
      )

      y += 1
    }

    x += 1
  }

  result
}

def invert(
    source: BufferedImage
): BufferedImage = {

  val result =
    new BufferedImage(
      source.getWidth,
      source.getHeight,
      BufferedImage.TYPE_INT_ARGB
    )

  var x = 0

  while (
    x < source.getWidth
  ) {

    var y = 0

    while (
      y < source.getHeight
    ) {

      val argb =
        source.getRGB(
          x,
          y
        )

      val a =
        (argb >>> 24) & 255

      val r =
        (argb >>> 16) & 255

      val g =
        (argb >>> 8
        ) & 255

      val b =
        argb & 255

      val out =
        (a << 24) |
        ((255 - r) << 16) |
        ((255 - g) << 8) |
        (255 - b)

      result.setRGB(
        x,
        y,
        out
      )

      y += 1
    }

    x += 1
  }

  result
}

// ============================================================
// TEACHER ENGINE
// ============================================================

def answerTeacher(
    input: String
): String = {

  val q =
    input.toLowerCase.trim

  if (
    q.isEmpty
  ) {

    "????? ??? question ????."

  } else if (
    q.contains("scala swing")
  ) {

    "Scala Swing ?????? Scala ????? graphical user interface applications ???? ???? ?????."

  } else if (
    q.contains("jframe")
  ) {

    "JFrame ????? application window ???. Scala ????? WindowConstants.EXIT_ON_CLOSE ?????? ????? ???."

  } else if (
    q.contains("button")
  ) {

    "JButton ?? clickable button ???. addActionListener ????? click ???????? ??????? code ?????? ????."

  } else if (
    q.contains("jpanel")
  ) {

    "JPanel ?? components group ???????????? container ???."

  } else if (
    q.contains("label")
  ) {

    "JLabel text, title ????? information ???????????? ?????? ????."

  } else if (
    q.contains("textfield")
  ) {

    "JTextField single-line user input ?????????? ?????? ????."

  } else if (
    q.contains("textarea")
  ) {

    "JTextArea notes, ???? text ??? code ???????????? ?????? ????."

  } else if (
    q.contains("mouse")
  ) {

    "MouseAdapter ?????? mouse click, press ??? release events handle ???? ?????."

  } else if (
    q.contains("keyboard")
  ) {

    "KeyAdapter ????? key bindings ?????? keyboard controls ???? ???? ?????."

  } else if (
    q.contains("timer")
  ) {

    "javax.swing.Timer ?????? countdown, animation ??? repeated actions ????? ?????."

  } else if (
    q.contains("clipboard")
  ) {

    "Clipboard ???? content ?????????? getContents(null) ???? Transferable ????? ??? ?????? isDataFlavorSupported ?????."

  } else if (
    q.contains("image")
  ) {

    "BufferedImage image memory ????? ????? ??? ImageIO ?????? image file save ???? ????."

  } else if (
    q.contains("game")
  ) {

    "Game ???? state variables, input, timer, collision detection, score, levels ??? repaint ?? ????? parts ????."

  } else if (
    q.contains("error") ||
    q.contains("compile")
  ) {

    "Compiler error ????? line number ???. ??????????? lines ???? braces, parentheses, quotes, commas, equals signs ??? declaration order ????? ?????."

  } else {

    "?? ?????? offline teacher library ????? ?????? ????. Question ???? ???? specific ????."
  }
}

// ============================================================
// LESSON DATA
// ============================================================

val lessonTitles =
  Array(
    "Scala Swing Basics",
    "JFrame",
    "JPanel",
    "JLabel",
    "JButton",
    "JTextField",
    "JTextArea",
    "Layouts",
    "Mouse Events",
    "Keyboard Events",
    "Timers",
    "Colors",
    "Fonts",
    "Menus",
    "Dialogs",
    "Files",
    "Clipboard",
    "Images",
    "Animation",
    "Mini Games",
    "Final Project"
  )

val lessonMarathi =
  Array(
    "?? ??? Scala Swing ?? basic ???? ?????? ????.",
    "JFrame ?? application ?? ????? window ????.",
    "JPanel ????? ??? components group ????.",
    "JLabel screen ?? text ??? titles ??????.",
    "JButton ?? click ???? action ?????? ????.",
    "JTextField ????? user input ???? ????.",
    "JTextArea notes ??? code ???????????? ?????? ???.",
    "Layout manager components arrange ????.",
    "Mouse events ?????? mouse interaction ???? ???? ????.",
    "Keyboard events ?????? keyboard controls ???? ???? ?????.",
    "Timer ?????? animation ??? countdown ???? ???? ?????.",
    "Colors ???? interface ????? ???? ????.",
    "Fonts ???? text design ???? ????.",
    "Menus ????? ???? commands ????? ?????.",
    "Dialogs user ?? messages ??? inputs ???? ?????? ?????.",
    "Files ????? code ??? notes save ???? ?????.",
    "Clipboard ?????? text ??? image copy paste ???? ????.",
    "BufferedImage ?????? image ???? ???? ????.",
    "Timer ??? repaint ?????? animation ???? ????.",
    "??? concepts ????? mini games ???? ???? ?????.",
    "??? ???? concepts ?????? final project ???? ???."
  )

val lessonEnglish =
  Array(
    "Learn the basic structure of Scala Swing.",
    "Create the main application window.",
    "Group UI components.",
    "Display text and titles.",
    "Handle button click events.",
    "Read text input.",
    "Create a code editor.",
    "Arrange components.",
    "Handle mouse input.",
    "Handle keyboard input.",
    "Create timers and animations.",
    "Design colors.",
    "Control fonts.",
    "Create menus.",
    "Use dialogs.",
    "Save and load files.",
    "Use the clipboard.",
    "Work with images.",
    "Create animations.",
    "Build mini games.",
    "Create the final project."
  )

// ============================================================
// FEATURE LIBRARY
// ============================================================

val featureLibrary =
  Array(
    "001 Dashboard",
    "002 Classroom",
    "003 Marathi Teacher",
    "004 Teacher Voice",
    "005 Stop Voice",
    "006 Play Lesson",
    "007 Replay Lesson",
    "008 Back Lesson",
    "009 Next Lesson",
    "010 Auto Next",

    "011 Progress",
    "012 Blackboard",
    "013 English Instructions",
    "014 Ask Teacher",
    "015 Question History",
    "016 Copy Answer",
    "017 Clear Answer",
    "018 Sample Question",
    "019 Teacher Tips",
    "020 Study Mode",

    "021 Code Lab",
    "022 Code Editor",
    "023 Copy Code",
    "024 Paste Code",
    "025 Save Code",
    "026 Load Code",
    "027 New Code",
    "028 Code Search",
    "029 Line Count",
    "030 Word Count",

    "031 Character Count",
    "032 Hello Template",
    "033 JFrame Template",
    "034 JButton Template",
    "035 JTextArea Template",
    "036 Timer Template",
    "037 Mouse Template",
    "038 Keyboard Template",
    "039 Game Template",
    "040 Login Template",

    "041 Error Fix",
    "042 Error Analyzer",
    "043 Declaration Fix",
    "044 Exit Constant Fix",
    "045 Forward Reference Fix",
    "046 Not Found Fix",
    "047 Type Mismatch Fix",
    "048 Expected Symbol Fix",
    "049 Scope Tips",
    "050 Import Tips",

    "051 Notes",
    "052 New Notes",
    "053 Save Notes",
    "054 Load Notes",
    "055 Copy Notes",
    "056 Paste Notes",
    "057 Uppercase",
    "058 Lowercase",
    "059 Reverse",
    "060 Note Statistics",

    "061 Tasks",
    "062 Add Task",
    "063 Complete Task",
    "064 Delete Task",
    "065 Clear Tasks",
    "066 Task Counter",
    "067 Study Goal",
    "068 Practice Goal",
    "069 Project Goal",
    "070 Progress",

    "071 Quiz",
    "072 Quiz Score",
    "073 Quiz Reset",
    "074 Multiple Questions",
    "075 Swing Quiz",
    "076 Scala Quiz",
    "077 Code Quiz",
    "078 Game Quiz",
    "079 Final Quiz",
    "080 Challenge",

    "081 Image Studio",
    "082 Local Artwork",
    "083 Upload Image",
    "084 Paste Image",
    "085 Copy Image",
    "086 Save Image",
    "087 Clear Image",
    "088 Image Info",
    "089 Grayscale",
    "090 Invert",

    "091 Image Preview",
    "092 Prompt Input",
    "093 Prompt Lab",
    "094 Code Prompt",
    "095 Game Prompt",
    "096 Debug Prompt",
    "097 Study Prompt",
    "098 Project Prompt",
    "099 Image Prompt",
    "100 Master Prompt",

    "101 Copy Prompt",
    "102 Project Builder",
    "103 Racing Idea",
    "104 Puzzle Idea",
    "105 Quiz Idea",
    "106 Calculator Idea",
    "107 Drawing Idea",
    "108 Chat Idea",
    "109 Study Idea",
    "110 AI Classroom Idea",

    "111 Utilities",
    "112 Uppercase",
    "113 Lowercase",
    "114 Reverse",
    "115 Clean Text",
    "116 Text Stats",
    "117 Clipboard Viewer",
    "118 Current Time",
    "119 Stopwatch",
    "120 Countdown",

    "121 Feature Search",
    "122 History",
    "123 Refresh History",
    "124 Export History",
    "125 Clear History",
    "126 Activity Log",
    "127 Settings",
    "128 Theme Control",
    "129 Font Control",
    "130 Help",

    "131 About",
    "132 Menu Bar",
    "133 File Menu",
    "134 Tools Menu",
    "135 Classroom Menu",
    "136 Project Menu",
    "137 Keyboard Shortcuts",
    "138 Ctrl+S",
    "139 Ctrl+L",
    "140 Ctrl+K",

    "141 Ctrl+Q",
    "142 Escape Stop",
    "143 F1 Help",
    "144 Scrollable Areas",
    "145 Search Fields",
    "146 Status Bar",
    "147 Clock",
    "148 Safe Clipboard",
    "149 Safe File Handling",
    "150 Safe Error Handling"
  )

// ============================================================
// LOGIN
// ============================================================

def openLogin(): Unit = {

  val frame =
    new JFrame(
      "Scala Swing AI Studio"
    )

  frame.setSize(
    540,
    350
  )

  frame.setLocationRelativeTo(null)

  frame.setDefaultCloseOperation(
    WindowConstants.EXIT_ON_CLOSE
  )

  val root =
    new JPanel(
      new BorderLayout(
        12,
        12
      )
    )

  root.setBackground(BG)

  root.setBorder(
    new EmptyBorder(
      25,
      25,
      25,
      25
    )
  )

  val title =
    makeLabel(
      "? SCALA SWING AI STUDIO",
      26,
      true
    )

  title.setHorizontalAlignment(
    SwingConstants.CENTER
  )

  root.add(
    title,
    BorderLayout.NORTH
  )

  val center =
    new JPanel()

  center.setBackground(BG)

  center.setLayout(
    new BoxLayout(
      center,
      BoxLayout.Y_AXIS
    )
  )

  val privateText =
    makeLabel(
      "PRIVATE LEARNING CLASSROOM",
      14,
      true
    )

  privateText.setAlignmentX(
    Component.CENTER_ALIGNMENT
  )

  val passwordField =
    new JPasswordField()

  passwordField.setMaximumSize(
    new Dimension(
      330,
      45
    )
  )

  passwordField.setFont(
    new Font(
      "Segoe UI",
      Font.PLAIN,
      18
    )
  )

  passwordField.setAlignmentX(
    Component.CENTER_ALIGNMENT
  )

  val enterButton =
    makeButton(
      "ENTER CLASSROOM"
    )

  enterButton.setAlignmentX(
    Component.CENTER_ALIGNMENT
  )

  val loginStatus =
    makeLabel(
      "READY",
      13,
      false
    )

  loginStatus.setAlignmentX(
    Component.CENTER_ALIGNMENT
  )

  center.add(
    privateText
  )

  center.add(
    Box.createVerticalStrut(20)
  )

  center.add(
    passwordField
  )

  center.add(
    Box.createVerticalStrut(15)
  )

  center.add(
    enterButton
  )

  center.add(
    Box.createVerticalStrut(10)
  )

  center.add(
    loginStatus
  )

  root.add(
    center,
    BorderLayout.CENTER
  )

  def checkLogin(): Unit = {

    val entered =
      new String(
        passwordField.getPassword
      )

    if (
      entered == passwordSecret
    ) {

      frame.dispose()

      openStudio()

    } else {

      loginStatus.setText(
        "ACCESS DENIED"
      )

      loginStatus.setForeground(
        RED
      )

      passwordField.setText("")
    }
  }

  enterButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        checkLogin()
      }
    }
  )

  passwordField.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        checkLogin()
      }
    }
  )

  frame.setContentPane(
    root
  )

  frame.setVisible(true)
}

// ============================================================
// MAIN STUDIO
// ============================================================

def openStudio(): Unit = {

  val frame =
    new JFrame(
      "Scala Swing AI Learning Studio"
    )

  frame.setSize(
    1500,
    920
  )

  frame.setLocationRelativeTo(null)

  frame.setDefaultCloseOperation(
    WindowConstants.EXIT_ON_CLOSE
  )

  val root =
    new JPanel(
      new BorderLayout()
    )

  root.setBackground(BG)

  // ==========================================================
  // TOP BAR
  // ==========================================================

  val topBar =
    new JPanel(
      new BorderLayout()
    )

  topBar.setBackground(
    new Color(
      9,
      11,
      16
    )
  )

  topBar.setBorder(
    new EmptyBorder(
      10,
      16,
      10,
      16
    )
  )

  val mainTitle =
    makeLabel(
      "? SCALA SWING AI LEARNING STUDIO",
      23,
      true
    )

  val readyLabel =
    makeLabel(
      "? READY",
      13,
      true
    )

  readyLabel.setForeground(
    GREEN
  )

  val stopVoiceButton =
    makeButton(
      "STOP VOICE"
    )

  stopVoiceButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        stopSpeech()

        readyLabel.setText(
          "? VOICE STOPPED"
        )

        readyLabel.setForeground(
          YELLOW
        )
      }
    }
  )

  val helpTopButton =
    makeButton(
      "HELP"
    )

  helpTopButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        showInfo(
          "Help",
          "Classroom = Lessons\n" +
          "Ask Teacher = Questions\n" +
          "Code Lab = Coding\n" +
          "Error Fix = Debugging\n" +
          "Image Studio = Images\n" +
          "Prompt Lab = Prompts\n" +
          "Projects = Project Builder\n" +
          "History = Activity Log"
        )
      }
    }
  )

  val topRight =
    new JPanel(
      new FlowLayout(
        FlowLayout.RIGHT,
        7,
        0
      )
    )

  topRight.setOpaque(false)

  topRight.add(
    readyLabel
  )

  topRight.add(
    stopVoiceButton
  )

  topRight.add(
    helpTopButton
  )

  topBar.add(
    mainTitle,
    BorderLayout.WEST
  )

  topBar.add(
    topRight,
    BorderLayout.EAST
  )

  root.add(
    topBar,
    BorderLayout.NORTH
  )

  // ==========================================================
  // TABS
  // ==========================================================

  val tabs =
    new JTabbedPane()

  tabs.setFont(
    new Font(
      "Segoe UI",
      Font.BOLD,
      13
    )
  )

  // ==========================================================
  // DASHBOARD
  // ==========================================================

  val dashboard =
    new JPanel(
      new BorderLayout(
        12,
        12
      )
    )

  dashboard.setBackground(BG)

  dashboard.setBorder(
    new EmptyBorder(
      15,
      15,
      15,
      15
    )
  )

  val dashTitle =
    makeLabel(
      "? MASTER DASHBOARD",
      27,
      true
    )

  val dashText =
    makeArea()

  dashText.setEditable(false)

  dashText.setFont(
    new Font(
      "Segoe UI",
      Font.PLAIN,
      18
    )
  )

  dashText.setText(
    "WELCOME TO THE ULTRA SCALA SWING STUDIO\n\n" +
    "Learn ? Practice ? Debug ? Build ? Create\n\n" +
    "MODULES\n\n" +
    "? Classroom\n" +
    "? Ask Teacher\n" +
    "? Code Lab\n" +
    "? Error Fix\n" +
    "? Notes\n" +
    "? Tasks\n" +
    "? Quiz\n" +
    "? Image Studio\n" +
    "? Prompt Lab\n" +
    "? Project Builder\n" +
    "? Utilities\n" +
    "? Feature Library\n" +
    "? Activity History\n" +
    "? Settings"
  )

  val dashButtons =
    new JPanel(
      new GridLayout(
        5,
        2,
        8,
        8
      )
    )

  dashButtons.setBackground(BG)

  val dashClass =
    makeButton("? CLASSROOM")

  val dashAsk =
    makeButton("? ASK TEACHER")

  val dashCode =
    makeButton("? CODE LAB")

  val dashError =
    makeButton("? ERROR FIX")

  val dashNotes =
    makeButton("? NOTES")

  val dashTasks =
    makeButton("? TASKS")

  val dashQuiz =
    makeButton("? QUIZ")

  val dashImage =
    makeButton("? IMAGE")

  val dashPrompt =
    makeButton("? PROMPTS")

  val dashProjects =
    makeButton("? PROJECTS")

  dashButtons.add(dashClass)
  dashButtons.add(dashAsk)
  dashButtons.add(dashCode)
  dashButtons.add(dashError)
  dashButtons.add(dashNotes)
  dashButtons.add(dashTasks)
  dashButtons.add(dashQuiz)
  dashButtons.add(dashImage)
  dashButtons.add(dashPrompt)
  dashButtons.add(dashProjects)

  val featureCountLabel =
    makeLabel(
      "REGISTERED FEATURES: " +
      featureLibrary.length,
      15,
      true
    )

  featureCountLabel.setForeground(
    GREEN
  )

  dashboard.add(
    dashTitle,
    BorderLayout.NORTH
  )

  dashboard.add(
    makeScroll(dashText),
    BorderLayout.CENTER
  )

  dashboard.add(
    dashButtons,
    BorderLayout.EAST
  )

  dashboard.add(
    featureCountLabel,
    BorderLayout.SOUTH
  )

  tabs.addTab(
    "? DASHBOARD",
    dashboard
  )

  // ==========================================================
  // CLASSROOM
  // ==========================================================

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

  classroom.setBackground(BG)

  classroom.setBorder(
    new EmptyBorder(
      12,
      12,
      12,
      12
    )
  )

  val board =
    new JTextArea()

  board.setEditable(false)

  board.setBackground(
    new Color(
      21,
      52,
      39
    )
  )

  board.setForeground(
    new Color(
      240,
      255,
      220
    )
  )

  board.setFont(
    new Font(
      "Consolas",
      Font.BOLD,
      22
    )
  )

  board.setBorder(
    new CompoundBorder(
      new LineBorder(
        new Color(
          135,
          95,
          45
        ),
        8
      ),
      new EmptyBorder(
        15,
        15,
        15,
        15
      )
    )
  )

  val teacherAvatar =
    makeLabel(
      "???",
      90,
      false
    )

  teacherAvatar.setHorizontalAlignment(
    SwingConstants.CENTER
  )

  val teacherState =
    makeLabel(
      "? READY",
      14,
      true
    )

  teacherState.setForeground(
    GREEN
  )

  teacherState.setHorizontalAlignment(
    SwingConstants.CENTER
  )

  val teacherSpeech =
    makeArea()

  teacherSpeech.setRows(7)
  teacherSpeech.setEditable(false)

  teacherSpeech.setFont(
    new Font(
      "Segoe UI",
      Font.PLAIN,
      18
    )
  )

  val teacherEnglish =
    makeArea()

  teacherEnglish.setRows(8)
  teacherEnglish.setEditable(false)

  teacherEnglish.setFont(
    new Font(
      "Consolas",
      Font.PLAIN,
      15
    )
  )

  val teacherPanel =
    new JPanel(
      new BorderLayout(
        7,
        7
      )
    )

  teacherPanel.setBackground(
    PANEL
  )

  teacherPanel.add(
    teacherAvatar,
    BorderLayout.NORTH
  )

  teacherPanel.add(
    makeScroll(teacherSpeech),
    BorderLayout.CENTER
  )

  teacherPanel.add(
    makeScroll(teacherEnglish),
    BorderLayout.SOUTH
  )

  val teacherMiddle =
    new JPanel(
      new GridLayout(
        1,
        2,
        10,
        10
      )
    )

  teacherMiddle.setBackground(BG)

  teacherMiddle.add(
    teacherPanel
  )

  val classroomActions =
    new JTextArea()

  classroomActions.setEditable(false)

  classroomActions.setBackground(
    PANEL
  )

  classroomActions.setForeground(
    TEXT
  )

  classroomActions.setFont(
    new Font(
      "Consolas",
      Font.BOLD,
      16
    )
  )

  classroomActions.setBorder(
    new EmptyBorder(
      15,
      15,
      15,
      15
    )
  )

  classroomActions.setText(
    "ENGLISH ACTION CHECKLIST\n\n" +
    "OPEN CHATGPT\n\n" +
    "READ THE QUESTION\n\n" +
    "COPY COMPLETE CODE\n\n" +
    "PASTE INTO SCALA EDITOR\n\n" +
    "SAVE THE FILE\n\n" +
    "RUN THE PROGRAM\n\n" +
    "CHECK RESULT\n\n" +
    "FIX ERROR\n\n" +
    "RUN AGAIN"
  )

  teacherMiddle.add(
    makeScroll(
      classroomActions
    )
  )

  val classroomControls =
    new JPanel(
      new FlowLayout(
        FlowLayout.CENTER,
        8,
        7
      )
    )

  classroomControls.setBackground(BG)

  val backLessonButton =
    makeButton(
      "? BACK"
    )

  val playLessonButton =
    makeButton(
      "? PLAY"
    )

  val replayLessonButton =
    makeButton(
      "? REPLAY"
    )

  val nextLessonButton =
    makeButton(
      "NEXT ?"
    )

  val autoNextCheck =
    new JCheckBox(
      "AUTO NEXT"
    )

  autoNextCheck.setSelected(true)
  autoNextCheck.setBackground(BG)
  autoNextCheck.setForeground(TEXT)

  val lessonProgress =
    makeLabel(
      "",
      14,
      true
    )

  classroomControls.add(
    backLessonButton
  )

  classroomControls.add(
    playLessonButton
  )

  classroomControls.add(
    replayLessonButton
  )

  classroomControls.add(
    nextLessonButton
  )

  classroomControls.add(
    autoNextCheck
  )

  classroomControls.add(
    lessonProgress
  )

  classroom.add(
    board,
    BorderLayout.NORTH
  )

  classroom.add(
    teacherMiddle,
    BorderLayout.CENTER
  )

  classroom.add(
    classroomControls,
    BorderLayout.SOUTH
  )

  def refreshLessonView(): Unit = {

    lessonProgress.setText(
      "LESSON " +
      (currentLesson + 1) +
      " / " +
      lessonTitles.length
    )

    board.setText(
      "SCALA SWING\n\n" +
      lessonTitles(currentLesson) +
      "\n\n" +
      lessonEnglish(currentLesson)
    )

    teacherSpeech.setText(
      lessonMarathi(currentLesson)
    )

    teacherEnglish.setText(
      "ENGLISH INSTRUCTIONS\n\n" +
      lessonEnglish(currentLesson) +
      "\n\n" +
      "OPEN CHATGPT\n" +
      "COPY COMPLETE CODE\n" +
      "PASTE\n" +
      "SAVE\n" +
      "RUN\n" +
      "CHECK"
    )
  }

  def playCurrentLesson(): Unit = {

    teacherState.setText(
      "? SPEAKING"
    )

    teacherState.setForeground(
      YELLOW
    )

    val lessonNumberAtStart =
      currentLesson

    speakText(
      lessonMarathi(
        currentLesson
      )
    )

    new Thread(
      new Runnable {

        def run(): Unit = {

          try {
            Thread.sleep(4000)
          } catch {
            case _: Throwable =>
          }

          SwingUtilities.invokeLater(
            new Runnable {

              def run(): Unit = {

                teacherState.setText(
                  "? READY"
                )

                teacherState.setForeground(
                  GREEN
                )

                if (
                  autoNextCheck.isSelected &&
                  autoNextEnabled &&
                  currentLesson ==
                    lessonNumberAtStart &&
                  currentLesson <
                    lessonTitles.length - 1
                ) {

                  currentLesson += 1

                  refreshLessonView()
                }
              }
            }
          )
        }
      }
    ).start()
  }

  backLessonButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        if (
          currentLesson > 0
        )
          currentLesson -= 1

        refreshLessonView()
      }
    }
  )

  nextLessonButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        if (
          currentLesson <
            lessonTitles.length - 1
        )
          currentLesson += 1

        refreshLessonView()
      }
    }
  )

  playLessonButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        playCurrentLesson()
      }
    }
  )

  replayLessonButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        playCurrentLesson()
      }
    }
  )

  autoNextCheck.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        autoNextEnabled =
          autoNextCheck.isSelected
      }
    }
  )

  refreshLessonView()

  tabs.addTab(
    "? CLASSROOM",
    classroom
  )

  // ==========================================================
  // ASK TEACHER
  // ==========================================================

  val askPanel =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  askPanel.setBackground(BG)

  askPanel.setBorder(
    new EmptyBorder(
      12,
      12,
      12,
      12
    )
  )

  val askInput =
    makeArea()

  askInput.setRows(7)

  val askOutput =
    makeArea()

  askOutput.setEditable(false)

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

  askButtons.setBackground(BG)

  val askQuestionButton =
    makeButton(
      "ASK"
    )

  val askSampleButton =
    makeButton(
      "SAMPLE"
    )

  val askCopyButton =
    makeButton(
      "COPY ANSWER"
    )

  val askClearButton =
    makeButton(
      "CLEAR"
    )

  val showQuestionHistoryButton =
    makeButton(
      "HISTORY"
    )

  askButtons.add(
    askQuestionButton
  )

  askButtons.add(
    askSampleButton
  )

  askButtons.add(
    askCopyButton
  )

  askButtons.add(
    askClearButton
  )

  askButtons.add(
    showQuestionHistoryButton
  )

  val askCenter =
    new JPanel(
      new GridLayout(
        2,
        1,
        8,
        8
      )
    )

  askCenter.setBackground(BG)

  val askInputBox =
    new JPanel(
      new BorderLayout()
    )

  askInputBox.setBackground(
    PANEL
  )

  askInputBox.add(
    makeLabel(
      "YOUR QUESTION",
      15,
      true
    ),
    BorderLayout.NORTH
  )

  askInputBox.add(
    makeScroll(
      askInput
    ),
    BorderLayout.CENTER
  )

  val askOutputBox =
    new JPanel(
      new BorderLayout()
    )

  askOutputBox.setBackground(
    PANEL
  )

  askOutputBox.add(
    makeLabel(
      "TEACHER ANSWER",
      15,
      true
    ),
    BorderLayout.NORTH
  )

  askOutputBox.add(
    makeScroll(
      askOutput
    ),
    BorderLayout.CENTER
  )

  askCenter.add(
    askInputBox
  )

  askCenter.add(
    askOutputBox
  )

  askPanel.add(
    makeLabel(
      "? ASK THE TEACHER",
      25,
      true
    ),
    BorderLayout.NORTH
  )

  askPanel.add(
    askCenter,
    BorderLayout.CENTER
  )

  askPanel.add(
    askButtons,
    BorderLayout.SOUTH
  )

  askQuestionButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        val q =
          askInput.getText.trim

        if (
          q.isEmpty
        ) {

          showWarning(
            "Question",
            "Please enter a question."
          )

        } else {

          questionHistory += q

          val result =
            answerTeacher(q)

          askOutput.setText(
            result
          )

          speakText(
            result
          )

          addActivity(
            "Teacher question answered"
          )
        }
      }
    }
  )

  askSampleButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        askInput.setText(
          "Scala Swing ????? JButton click event ??? ???????"
        )
      }
    }
  )

  askCopyButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        copyText(
          askOutput.getText
        )
      }
    }
  )

  askClearButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        askInput.setText("")
        askOutput.setText("")
      }
    }
  )

  showQuestionHistoryButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        if (
          questionHistory.isEmpty
        ) {

          showInfo(
            "History",
            "No questions yet."
          )

        } else {

          showInfo(
            "Question History",
            questionHistory
              .reverse
              .take(50)
              .mkString(
                "\n\n"
              )
          )
        }
      }
    }
  )

  tabs.addTab(
    "? ASK TEACHER",
    askPanel
  )

  // ==========================================================
  // CODE LAB
  // ==========================================================

  val codePanel =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  codePanel.setBackground(BG)

  codePanel.setBorder(
    new EmptyBorder(
      12,
      12,
      12,
      12
    )
  )

  val codeEditor =
    makeArea()

  codeEditor.setFont(
    new Font(
      "Consolas",
      Font.PLAIN,
      16
    )
  )

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

  codeTools.setBackground(BG)

  val newCodeButton =
    makeButton(
      "NEW"
    )

  val copyCodeButton =
    makeButton(
      "COPY"
    )

  val pasteCodeButton =
    makeButton(
      "PASTE"
    )

  val saveCodeButton =
    makeButton(
      "SAVE"
    )

  val loadCodeButton =
    makeButton(
      "LOAD"
    )

  val codeStatsButton =
    makeButton(
      "STATS"
    )

  val codeSearchField =
    makeField()

  codeSearchField.setPreferredSize(
    new Dimension(
      180,
      38
    )
  )

  val codeSearchButton =
    makeButton(
      "SEARCH"
    )

  val templateBox =
    new JComboBox[String](
      Array(
        "Hello World",
        "JFrame",
        "JButton",
        "JTextArea",
        "Timer",
        "Mouse",
        "Keyboard",
        "Mini Game",
        "Login UI",
        "Notes"
      )
    )

  codeTools.add(
    newCodeButton
  )

  codeTools.add(
    copyCodeButton
  )

  codeTools.add(
    pasteCodeButton
  )

  codeTools.add(
    saveCodeButton
  )

  codeTools.add(
    loadCodeButton
  )

  codeTools.add(
    codeStatsButton
  )

  codeTools.add(
    templateBox
  )

  codeTools.add(
    codeSearchField
  )

  codeTools.add(
    codeSearchButton
  )

  codePanel.add(
    makeLabel(
      "? CODE LAB",
      25,
      true
    ),
    BorderLayout.NORTH
  )

  codePanel.add(
    makeScroll(
      codeEditor
    ),
    BorderLayout.CENTER
  )

  codePanel.add(
    codeTools,
    BorderLayout.SOUTH
  )

  newCodeButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        codeEditor.setText("")
      }
    }
  )

  copyCodeButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        copyText(
          codeEditor.getText
        )
      }
    }
  )

  pasteCodeButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        val text =
          pasteText()

        if (
          text.nonEmpty
        )
          codeEditor.insert(
            text,
            codeEditor.getCaretPosition
          )
      }
    }
  )

  saveCodeButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        saveTextFile(
          codeEditor.getText,
          "ScalaCode.scala"
        )
      }
    }
  )

  loadCodeButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        loadTextFile(
          codeEditor
        )
      }
    }
  )

  codeStatsButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        val text =
          codeEditor.getText

        showInfo(
          "Code Statistics",
          "Lines: " +
          text.split(
            "\n",
            -1
          ).length +
          "\nWords: " +
          text.split(
            "\\s+"
          ).count(
            _.nonEmpty
          ) +
          "\nCharacters: " +
          text.length
        )
      }
    }
  )

  codeSearchButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        val find =
          codeSearchField.getText

        val text =
          codeEditor.getText

        val pos =
          if (find.isEmpty)
            -1
          else
            text.indexOf(find)

        if (
          pos >= 0
        ) {

          codeEditor.requestFocus()

          codeEditor.select(
            pos,
            pos + find.length
          )

        } else {

          showInfo(
            "Search",
            "Text not found."
          )
        }
      }
    }
  )

  templateBox.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        val selected =
          templateBox
            .getSelectedItem
            .toString

        val templateCode =
          if (
            selected ==
              "Hello World"
          ) {

            "println(\"Hello Scala!\")"

          } else if (
            selected ==
              "JFrame"
          ) {

            "import javax.swing._\n\n" +
            "val frame = new JFrame(\"My App\")\n" +
            "frame.setSize(700,500)\n" +
            "frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)\n" +
            "frame.setVisible(true)"

          } else if (
            selected ==
              "JButton"
          ) {

            "import javax.swing._\n" +
            "import java.awt.event._\n\n" +
            "val button = new JButton(\"CLICK\")\n\n" +
            "button.addActionListener(new ActionListener {\n" +
            "  def actionPerformed(e: ActionEvent): Unit = {\n" +
            "    println(\"Clicked\")\n" +
            "  }\n" +
            "})"

          } else if (
            selected ==
              "JTextArea"
          ) {

            "val area = new JTextArea()\n" +
            "area.setText(\"Write here...\")"

          } else if (
            selected ==
              "Timer"
          ) {

            "val timer = new javax.swing.Timer(1000, new java.awt.event.ActionListener {\n" +
            "  def actionPerformed(e: java.awt.event.ActionEvent): Unit = {\n" +
            "    println(\"Tick\")\n" +
            "  }\n" +
            "})\n" +
            "timer.start()"

          } else if (
            selected ==
              "Mouse"
          ) {

            "panel.addMouseListener(new java.awt.event.MouseAdapter {\n" +
            "  override def mouseClicked(e: java.awt.event.MouseEvent): Unit = {\n" +
            "    println(e.getX + \",\" + e.getY)\n" +
            "  }\n" +
            "})"

          } else if (
            selected ==
              "Keyboard"
          ) {

            "panel.addKeyListener(new java.awt.event.KeyAdapter {\n" +
            "  override def keyPressed(e: java.awt.event.KeyEvent): Unit = {\n" +
            "    println(e.getKeyCode)\n" +
            "  }\n" +
            "})"

          } else if (
            selected ==
              "Mini Game"
          ) {

            "var score = 0\n" +
            "var running = true\n" +
            "println(\"Game started\")"

          } else if (
            selected ==
              "Login UI"
          ) {

            "val password = new JPasswordField()\n" +
            "val login = new JButton(\"LOGIN\")"

          } else {

            "val notes = new JTextArea()\n" +
            "notes.setText(\"My Notes\")"
          }

        codeEditor.setText(
          templateCode
        )
      }
    }
  )

  tabs.addTab(
    "? CODE LAB",
    codePanel
  )

  // ==========================================================
  // ERROR FIX
  // ==========================================================

  val errorPanel =
    new JPanel(
      new GridLayout(
        2,
        1,
        8,
        8
      )
    )

  errorPanel.setBackground(BG)

  errorPanel.setBorder(
    new EmptyBorder(
      12,
      12,
      12,
      12
    )
  )

  val errorInput =
    makeArea()

  val errorOutput =
    makeArea()

  errorOutput.setEditable(false)

  val analyzeErrorButton =
    makeButton(
      "ANALYZE ERROR"
    )

  val errorTop =
    new JPanel(
      new BorderLayout()
    )

  errorTop.setBackground(BG)

  errorTop.add(
    makeLabel(
      "ERROR INPUT",
      17,
      true
    ),
    BorderLayout.WEST
  )

  errorTop.add(
    analyzeErrorButton,
    BorderLayout.EAST
  )

  val errorBox1 =
    new JPanel(
      new BorderLayout()
    )

  errorBox1.setBackground(PANEL)

  errorBox1.add(
    errorTop,
    BorderLayout.NORTH
  )

  errorBox1.add(
    makeScroll(
      errorInput
    ),
    BorderLayout.CENTER
  )

  val errorBox2 =
    new JPanel(
      new BorderLayout()
    )

  errorBox2.setBackground(PANEL)

  errorBox2.add(
    makeLabel(
      "TEACHER FIX",
      17,
      true
    ),
    BorderLayout.NORTH
  )

  errorBox2.add(
    makeScroll(
      errorOutput
    ),
    BorderLayout.CENTER
  )

  errorPanel.add(
    errorBox1
  )

  errorPanel.add(
    errorBox2
  )

  analyzeErrorButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        val text =
          errorInput
            .getText
            .toLowerCase

        val result =
          if (
            text.contains(
              "illegal start of declaration"
            )
          ) {

            "CHECK:\n\n" +
            "? Missing { or }\n" +
            "? Missing =\n" +
            "? Statement outside block\n" +
            "? Previous line syntax error\n" +
            "? Incorrect method structure"

          } else if (
            text.contains(
              "exit_on_close"
            )
          ) {

            "USE:\n\n" +
            "WindowConstants.EXIT_ON_CLOSE"

          } else if (
            text.contains(
              "forward reference"
            )
          ) {

            "A variable or value is being used before it is safely initialized.\n\n" +
            "Move the declaration earlier."

          } else if (
            text.contains(
              "not found"
            )
          ) {

            "Check:\n\n" +
            "? import\n" +
            "? spelling\n" +
            "? scope\n" +
            "? declaration order"

          } else if (
            text.contains(
              "type mismatch"
            )
          ) {

            "Expected type and actual type are different.\n\n" +
            "Check String, Int, Double, Boolean and component types."

          } else {

            "Paste the COMPLETE compiler error with the line number."
          }

        errorOutput.setText(
          result
        )

        addActivity(
          "Error analyzed"
        )

        speakText(
          result
        )
      }
    }
  )

  tabs.addTab(
    "? ERROR FIX",
    errorPanel
  )

  // ==========================================================
  // NOTES
  // ==========================================================

  val notesPanel =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  notesPanel.setBackground(BG)

  notesPanel.setBorder(
    new EmptyBorder(
      12,
      12,
      12,
      12
    )
  )

  val notesArea =
    makeArea()

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

  noteButtons.setBackground(BG)

  val newNoteButton =
    makeButton("NEW")

  val saveNoteButton =
    makeButton("SAVE")

  val loadNoteButton =
    makeButton("LOAD")

  val copyNoteButton =
    makeButton("COPY")

  val pasteNoteButton =
    makeButton("PASTE")

  val upperNoteButton =
    makeButton("UPPER")

  val lowerNoteButton =
    makeButton("LOWER")

  val reverseNoteButton =
    makeButton("REVERSE")

  val noteStatsButton =
    makeButton("STATS")

  noteButtons.add(
    newNoteButton
  )

  noteButtons.add(
    saveNoteButton
  )

  noteButtons.add(
    loadNoteButton
  )

  noteButtons.add(
    copyNoteButton
  )

  noteButtons.add(
    pasteNoteButton
  )

  noteButtons.add(
    upperNoteButton
  )

  noteButtons.add(
    lowerNoteButton
  )

  noteButtons.add(
    reverseNoteButton
  )

  noteButtons.add(
    noteStatsButton
  )

  notesPanel.add(
    makeLabel(
      "? NOTES & TEXT LAB",
      25,
      true
    ),
    BorderLayout.NORTH
  )

  notesPanel.add(
    makeScroll(
      notesArea
    ),
    BorderLayout.CENTER
  )

  notesPanel.add(
    noteButtons,
    BorderLayout.SOUTH
  )

  newNoteButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        notesArea.setText("")
      }
    }
  )

  saveNoteButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        saveTextFile(
          notesArea.getText,
          "MyNotes.txt"
        )
      }
    }
  )

  loadNoteButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        loadTextFile(
          notesArea
        )
      }
    }
  )

  copyNoteButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        copyText(
          notesArea.getText
        )
      }
    }
  )

  pasteNoteButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        val text =
          pasteText()

        if (
          text.nonEmpty
        )
          notesArea.insert(
            text,
            notesArea.getCaretPosition
          )
      }
    }
  )

  upperNoteButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        notesArea.setText(
          notesArea
            .getText
            .toUpperCase
        )
      }
    }
  )

  lowerNoteButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        notesArea.setText(
          notesArea
            .getText
            .toLowerCase
        )
      }
    }
  )

  reverseNoteButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        notesArea.setText(
          notesArea
            .getText
            .reverse
        )
      }
    }
  )

  noteStatsButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        val text =
          notesArea.getText

        showInfo(
          "Notes Statistics",
          "Characters: " +
          text.length +
          "\nWords: " +
          text.split(
            "\\s+"
          ).count(
            _.nonEmpty
          ) +
          "\nLines: " +
          text.split(
            "\n",
            -1
          ).length
        )
      }
    }
  )

  tabs.addTab(
    "? NOTES",
    notesPanel
  )

  // ==========================================================
  // TASK MANAGER
  // ==========================================================

  val taskPanel =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  taskPanel.setBackground(BG)

  taskPanel.setBorder(
    new EmptyBorder(
      12,
      12,
      12,
      12
    )
  )

  val taskModel =
    new DefaultListModel[String]()

  val taskList =
    new JList[String](
      taskModel
    )

  taskList.setBackground(PANEL3)
  taskList.setForeground(TEXT)

  taskList.setFont(
    new Font(
      "Segoe UI",
      Font.PLAIN,
      17
    )
  )

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

  taskTools.setBackground(BG)

  val addTaskButton =
    makeButton(
      "ADD TASK"
    )

  val completeTaskButton =
    makeButton(
      "DONE"
    )

  val deleteTaskButton =
    makeButton(
      "DELETE"
    )

  val clearTaskButton =
    makeButton(
      "CLEAR ALL"
    )

  taskTools.add(
    addTaskButton
  )

  taskTools.add(
    completeTaskButton
  )

  taskTools.add(
    deleteTaskButton
  )

  taskTools.add(
    clearTaskButton
  )

  taskPanel.add(
    makeLabel(
      "? TASK MANAGER",
      25,
      true
    ),
    BorderLayout.NORTH
  )

  taskPanel.add(
    makeScroll(
      taskList
    ),
    BorderLayout.CENTER
  )

  taskPanel.add(
    taskTools,
    BorderLayout.SOUTH
  )

  addTaskButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        val text =
          JOptionPane.showInputDialog(
            frame,
            "New task:"
          )

        if (
          text != null &&
          text.trim.nonEmpty
        ) {

          taskModel.addElement(
            "? " +
            text.trim
          )

          addActivity(
            "Task added"
          )
        }
      }
    }
  )

  completeTaskButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        val index =
          taskList.getSelectedIndex

        if (
          index >= 0
        ) {

          val old =
            taskModel.get(index)

          if (
            !old.startsWith("?")
          ) {

            taskModel.set(
              index,
              "? " +
              old.drop(2)
            )
          }
        }
      }
    }
  )

  deleteTaskButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        val index =
          taskList.getSelectedIndex

        if (
          index >= 0
        )
          taskModel.remove(index)
      }
    }
  )

  clearTaskButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        taskModel.clear()
      }
    }
  )

  tabs.addTab(
    "? TASKS",
    taskPanel
  )

  // ==========================================================
  // QUIZ
  // ==========================================================

  val quizPanel =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  quizPanel.setBackground(BG)

  quizPanel.setBorder(
    new EmptyBorder(
      12,
      12,
      12,
      12
    )
  )

  val quizQuestionLabel =
    makeLabel(
      "",
      21,
      true
    )

  val quizScoreLabel =
    makeLabel(
      "Score: 0",
      15,
      true
    )

  quizScoreLabel.setForeground(
    GREEN
  )

  val quizAnswersPanel =
    new JPanel()

  quizAnswersPanel.setBackground(BG)

  quizAnswersPanel.setLayout(
    new BoxLayout(
      quizAnswersPanel,
      BoxLayout.Y_AXIS
    )
  )

  val quizQuestions =
    Array(
      (
        "Which component is a button?",
        "JButton",
        Array(
          "JButton",
          "JLabel",
          "JPanel",
          "JFrame"
        )
      ),
      (
        "Which constant is correct for close?",
        "WindowConstants",
        Array(
          "Color",
          "WindowConstants",
          "MouseEvent",
          "ImageIO"
        )
      ),
      (
        "Which component is multi-line?",
        "JTextArea",
        Array(
          "JTextField",
          "JTextArea",
          "JButton",
          "JLabel"
        )
      ),
      (
        "Which class is Swing timer?",
        "javax.swing.Timer",
        Array(
          "File",
          "Color",
          "javax.swing.Timer",
          "Font"
        )
      ),
      (
        "Which class saves images?",
        "ImageIO",
        Array(
          "ImageIO",
          "JButton",
          "JPanel",
          "JFrame"
        )
      )
    )

  def refreshQuiz(): Unit = {

    quizQuestionLabel.setText(
      quizQuestions(
        quizIndex
      )._1 +
      "    Question " +
      (quizIndex + 1) +
      "/" +
      quizQuestions.length
    )

    quizAnswersPanel.removeAll()

    val choices =
      quizQuestions(
        quizIndex
      )._3

    var i = 0

    while (
      i < choices.length
    ) {

      val choice =
        choices(i)

      val answerButton =
        makeButton(
          choice
        )

      answerButton.setAlignmentX(
        Component.LEFT_ALIGNMENT
      )

      answerButton.addActionListener(
        new ActionListener {

          def actionPerformed(
              e: ActionEvent
          ): Unit = {

            if (
              choice ==
                quizQuestions(
                  quizIndex
                )._2
            ) {

              quizScore += 1
            }

            quizIndex += 1

            if (
              quizIndex >=
                quizQuestions.length
            ) {

              showInfo(
                "Quiz Finished",
                "Score: " +
                quizScore +
                "/" +
                quizQuestions.length
              )

              quizScore = 0
              quizIndex = 0
            }

            quizScoreLabel.setText(
              "Score: " +
              quizScore
            )

            refreshQuiz()
          }
        }
      )

      quizAnswersPanel.add(
        answerButton
      )

      quizAnswersPanel.add(
        Box.createVerticalStrut(8)
      )

      i += 1
    }

    quizAnswersPanel.revalidate()
    quizAnswersPanel.repaint()
  }

  val quizHeader =
    new JPanel(
      new BorderLayout()
    )

  quizHeader.setBackground(BG)

  quizHeader.add(
    makeLabel(
      "? SCALA SWING QUIZ",
      25,
      true
    ),
    BorderLayout.WEST
  )

  quizHeader.add(
    quizScoreLabel,
    BorderLayout.EAST
  )

  quizPanel.add(
    quizHeader,
    BorderLayout.NORTH
  )

  quizPanel.add(
    quizQuestionLabel,
    BorderLayout.CENTER
  )

  quizPanel.add(
    makeScroll(
      quizAnswersPanel
    ),
    BorderLayout.SOUTH
  )

  refreshQuiz()

  tabs.addTab(
    "? QUIZ",
    quizPanel
  )

  // ==========================================================
  // IMAGE STUDIO
  // ==========================================================

  val imagePanel =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  imagePanel.setBackground(BG)

  imagePanel.setBorder(
    new EmptyBorder(
      12,
      12,
      12,
      12
    )
  )

  val imagePromptField =
    makeField()

  val imagePreview =
    new JLabel(
      "IMAGE PREVIEW",
      SwingConstants.CENTER
    )

  imagePreview.setOpaque(true)
  imagePreview.setBackground(
    new Color(
      8,
      11,
      17
    )
  )

  imagePreview.setForeground(
    SUBTEXT
  )

  imagePreview.setFont(
    new Font(
      "Segoe UI",
      Font.BOLD,
      22
    )
  )

  val imageTop =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  imageTop.setBackground(BG)

  imageTop.add(
    makeLabel(
      "PROMPT",
      14,
      true
    ),
    BorderLayout.WEST
  )

  imageTop.add(
    imagePromptField,
    BorderLayout.CENTER
  )

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

  imageButtons.setBackground(BG)

  val generateImageButton =
    makeButton(
      "GENERATE"
    )

  val uploadImageButton =
    makeButton(
      "UPLOAD"
    )

  val pasteImageButton =
    makeButton(
      "PASTE"
    )

  val copyImageButton =
    makeButton(
      "COPY"
    )

  val saveImageButton =
    makeButton(
      "SAVE"
    )

  val clearImageButton =
    makeButton(
      "CLEAR"
    )

  val grayscaleButton =
    makeButton(
      "GRAYSCALE"
    )

  val invertButton =
    makeButton(
      "INVERT"
    )

  val imageInfoButton =
    makeButton(
      "INFO"
    )

  imageButtons.add(
    generateImageButton
  )

  imageButtons.add(
    uploadImageButton
  )

  imageButtons.add(
    pasteImageButton
  )

  imageButtons.add(
    copyImageButton
  )

  imageButtons.add(
    saveImageButton
  )

  imageButtons.add(
    clearImageButton
  )

  imageButtons.add(
    grayscaleButton
  )

  imageButtons.add(
    invertButton
  )

  imageButtons.add(
    imageInfoButton
  )

  imagePanel.add(
    makeLabel(
      "? IMAGE STUDIO",
      25,
      true
    ),
    BorderLayout.NORTH
  )

  val imageCenter =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  imageCenter.setBackground(BG)

  imageCenter.add(
    imageTop,
    BorderLayout.NORTH
  )

  imageCenter.add(
    imagePreview,
    BorderLayout.CENTER
  )

  imagePanel.add(
    imageCenter,
    BorderLayout.CENTER
  )

  imagePanel.add(
    imageButtons,
    BorderLayout.SOUTH
  )

  generateImageButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        savedImage =
          createArtwork(
            imagePromptField.getText
          )

        updateImagePreview(
          imagePreview
        )

        addActivity(
          "Artwork generated"
        )
      }
    }
  )

  uploadImageButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        val chooser =
          new JFileChooser()

        if (
          chooser.showOpenDialog(
            frame
          ) ==
            JFileChooser.APPROVE_OPTION
        ) {

          try {

            savedImage =
              ImageIO.read(
                chooser.getSelectedFile
              )

            if (
              savedImage == null
            ) {

              showWarning(
                "Image",
                "Invalid image file."
              )

            } else {

              updateImagePreview(
                imagePreview
              )

              addActivity(
                "Image uploaded"
              )
            }

          } catch {

            case _: Throwable =>

              showWarning(
                "Image",
                "Image loading failed."
              )
          }
        }
      }
    }
  )

  pasteImageButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        if (
          pasteImage()
        ) {

          updateImagePreview(
            imagePreview
          )

        } else {

          showWarning(
            "Clipboard",
            "Clipboard ????? image ?????? ????."
          )
        }
      }
    }
  )

  copyImageButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        copyImage()
      }
    }
  )

  saveImageButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        if (
          savedImage == null
        ) {

          showWarning(
            "Image",
            "Save ?????????? image ????."
          )

        } else {

          val chooser =
            new JFileChooser()

          chooser.setSelectedFile(
            new File(
              "MyImage.png"
            )
          )

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

            try {

              ImageIO.write(
                savedImage,
                "png",
                chooser.getSelectedFile
              )

              addActivity(
                "Image saved"
              )

            } catch {

              case _: Throwable =>

                showWarning(
                  "Image",
                  "Image save failed."
                )
            }
          }
        }
      }
    }
  )

  clearImageButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        savedImage = null

        imagePreview.setIcon(null)

        imagePreview.setText(
          "IMAGE PREVIEW"
        )
      }
    }
  )

  grayscaleButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        if (
          savedImage != null
        ) {

          savedImage =
            grayscale(
              savedImage
            )

          updateImagePreview(
            imagePreview
          )
        }
      }
    }
  )

  invertButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        if (
          savedImage != null
        ) {

          savedImage =
            invert(
              savedImage
            )

          updateImagePreview(
            imagePreview
          )
        }
      }
    }
  )

  imageInfoButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        if (
          savedImage == null
        ) {

          showInfo(
            "Image Info",
            "No image loaded."
          )

        } else {

          showInfo(
            "Image Info",
            "Width: " +
            savedImage.getWidth +
            "\nHeight: " +
            savedImage.getHeight
          )
        }
      }
    }
  )

  tabs.addTab(
    "? IMAGE STUDIO",
    imagePanel
  )

  // ==========================================================
  // PROMPT LAB
  // ==========================================================

  val promptPanel =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  promptPanel.setBackground(BG)

  promptPanel.setBorder(
    new EmptyBorder(
      12,
      12,
      12,
      12
    )
  )

  val promptOutput =
    makeArea()

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

  promptButtons.setBackground(BG)

  val promptCode =
    makeButton(
      "CODE"
    )

  val promptGame =
    makeButton(
      "GAME"
    )

  val promptDebug =
    makeButton(
      "DEBUG"
    )

  val promptStudy =
    makeButton(
      "STUDY"
    )

  val promptProject =
    makeButton(
      "PROJECT"
    )

  val promptImage =
    makeButton(
      "IMAGE"
    )

  val promptMaster =
    makeButton(
      "MASTER"
    )

  val promptCopy =
    makeButton(
      "COPY"
    )

  promptButtons.add(promptCode)
  promptButtons.add(promptGame)
  promptButtons.add(promptDebug)
  promptButtons.add(promptStudy)
  promptButtons.add(promptProject)
  promptButtons.add(promptImage)
  promptButtons.add(promptMaster)
  promptButtons.add(promptCopy)

  promptPanel.add(
    makeLabel(
      "? PROMPT LAB",
      25,
      true
    ),
    BorderLayout.NORTH
  )

  promptPanel.add(
    makeScroll(
      promptOutput
    ),
    BorderLayout.CENTER
  )

  promptPanel.add(
    promptButtons,
    BorderLayout.SOUTH
  )

  promptCode.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        promptOutput.setText(
          "Create a complete Scala Swing application.\n" +
          "Use one file.\n" +
          "Avoid unnecessary dependencies.\n" +
          "Return complete runnable code.\n" +
          "Check declaration order and syntax."
        )
      }
    }
  )

  promptGame.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        promptOutput.setText(
          "Create an original Scala Swing game.\n" +
          "Include player controls, score, levels,\n" +
          "collision detection, restart, win screen,\n" +
          "keyboard input and polished UI."
        )
      }
    }
  )

  promptDebug.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        promptOutput.setText(
          "Fix my Scala compiler error.\n" +
          "Return complete corrected code.\n" +
          "Do not give only a tiny patch.\n" +
          "Preserve existing features."
        )
      }
    }
  )

  promptStudy.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        promptOutput.setText(
          "Teach Scala Swing step by step.\n" +
          "Explain concepts in simple Marathi.\n" +
          "Keep action instructions in English.\n" +
          "Give practical examples."
        )
      }
    }
  )

  promptProject.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        promptOutput.setText(
          "Build a large all-in-one Scala Swing project.\n" +
          "Include navigation, notes, search,\n" +
          "utilities, animation, error handling and polished design."
        )
      }
    }
  )

  promptImage.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        promptOutput.setText(
          "Create a detailed image prompt with:\n" +
          "subject, environment, lighting, composition,\n" +
          "camera, mood, materials and visual details."
        )
      }
    }
  )

  promptMaster.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        promptOutput.setText(
          "You are an expert Scala Swing developer and teacher.\n" +
          "Create stable complete applications.\n" +
          "Use one file when possible.\n" +
          "Avoid unnecessary dependencies.\n" +
          "Check declaration order, braces and syntax.\n" +
          "Use WindowConstants.EXIT_ON_CLOSE."
        )
      }
    }
  )

  promptCopy.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        copyText(
          promptOutput.getText
        )
      }
    }
  )

  tabs.addTab(
    "? PROMPT LAB",
    promptPanel
  )

  // ==========================================================
  // PROJECT BUILDER
  // ==========================================================

  val projectPanel =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  projectPanel.setBackground(BG)

  projectPanel.setBorder(
    new EmptyBorder(
      12,
      12,
      12,
      12
    )
  )

  val projectOutput =
    makeArea()

  projectOutput.setEditable(false)

  val projectButtons =
    new JPanel(
      new GridLayout(
        2,
        5,
        8,
        8
      )
    )

  projectButtons.setBackground(BG)

  val projectNames =
    Array(
      "Racing Game",
      "Puzzle Game",
      "Quiz App",
      "Calculator",
      "Drawing App",
      "Chat UI",
      "Detective App",
      "Study App",
      "AI Classroom",
      "Music UI"
    )

  var projectCounter = 0

  while (
    projectCounter <
      projectNames.length
  ) {

    val name =
      projectNames(
        projectCounter
      )

    val projectButton =
      makeButton(name)

    projectButton.addActionListener(
      new ActionListener {

        def actionPerformed(
            e: ActionEvent
        ): Unit = {

          projectOutput.setText(
            "PROJECT: " +
            name +
            "\n\n" +
            "MODULE PLAN\n\n" +
            "1. Main Window\n" +
            "2. Navigation\n" +
            "3. State Management\n" +
            "4. Input\n" +
            "5. Components\n" +
            "6. Data\n" +
            "7. Save / Load\n" +
            "8. Error Handling\n" +
            "9. Testing\n" +
            "10. Final Polish"
          )
        }
      }
    )

    projectButtons.add(
      projectButton
    )

    projectCounter += 1
  }

  projectPanel.add(
    makeLabel(
      "? PROJECT BUILDER",
      25,
      true
    ),
    BorderLayout.NORTH
  )

  projectPanel.add(
    makeScroll(
      projectOutput
    ),
    BorderLayout.CENTER
  )

  projectPanel.add(
    projectButtons,
    BorderLayout.SOUTH
  )

  tabs.addTab(
    "? PROJECTS",
    projectPanel
  )

  // ==========================================================
  // UTILITIES
  // ==========================================================

  val utilityPanel =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  utilityPanel.setBackground(BG)

  utilityPanel.setBorder(
    new EmptyBorder(
      12,
      12,
      12,
      12
    )
  )

  val utilityInput =
    makeArea()

  val utilityOutput =
    makeArea()

  utilityOutput.setEditable(false)

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

  utilityButtons.setBackground(BG)

  val upperButton =
    makeButton("UPPER")

  val lowerButton =
    makeButton("LOWER")

  val reverseButton =
    makeButton("REVERSE")

  val cleanButton =
    makeButton("CLEAN")

  val statsButton =
    makeButton("STATS")

  val clipboardButton =
    makeButton("CLIPBOARD")

  val timeButton =
    makeButton("TIME")

  utilityButtons.add(
    upperButton
  )

  utilityButtons.add(
    lowerButton
  )

  utilityButtons.add(
    reverseButton
  )

  utilityButtons.add(
    cleanButton
  )

  utilityButtons.add(
    statsButton
  )

  utilityButtons.add(
    clipboardButton
  )

  utilityButtons.add(
    timeButton
  )

  val utilityCenter =
    new JPanel(
      new GridLayout(
        2,
        1,
        8,
        8
      )
    )

  utilityCenter.setBackground(BG)

  val utilityInputBox =
    new JPanel(
      new BorderLayout()
    )

  utilityInputBox.setBackground(
    PANEL
  )

  utilityInputBox.add(
    makeLabel(
      "INPUT",
      15,
      true
    ),
    BorderLayout.NORTH
  )

  utilityInputBox.add(
    makeScroll(
      utilityInput
    ),
    BorderLayout.CENTER
  )

  val utilityOutputBox =
    new JPanel(
      new BorderLayout()
    )

  utilityOutputBox.setBackground(
    PANEL
  )

  utilityOutputBox.add(
    makeLabel(
      "OUTPUT",
      15,
      true
    ),
    BorderLayout.NORTH
  )

  utilityOutputBox.add(
    makeScroll(
      utilityOutput
    ),
    BorderLayout.CENTER
  )

  utilityCenter.add(
    utilityInputBox
  )

  utilityCenter.add(
    utilityOutputBox
  )

  utilityPanel.add(
    makeLabel(
      "? UTILITIES",
      25,
      true
    ),
    BorderLayout.NORTH
  )

  utilityPanel.add(
    utilityCenter,
    BorderLayout.CENTER
  )

  utilityPanel.add(
    utilityButtons,
    BorderLayout.SOUTH
  )

  upperButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        utilityOutput.setText(
          utilityInput
            .getText
            .toUpperCase
        )
      }
    }
  )

  lowerButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        utilityOutput.setText(
          utilityInput
            .getText
            .toLowerCase
        )
      }
    }
  )

  reverseButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        utilityOutput.setText(
          utilityInput
            .getText
            .reverse
        )
      }
    }
  )

  cleanButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        utilityOutput.setText(
          utilityInput
            .getText
            .split("\n")
            .map(
              _.trim
            )
            .filter(
              _.nonEmpty
            )
            .mkString(
              "\n"
            )
        )
      }
    }
  )

  statsButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        val text =
          utilityInput.getText

        utilityOutput.setText(
          "Characters: " +
          text.length +
          "\nWords: " +
          text.split(
            "\\s+"
          ).count(
            _.nonEmpty
          ) +
          "\nLines: " +
          text.split(
            "\n",
            -1
          ).length
        )
      }
    }
  )

  clipboardButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        utilityOutput.setText(
          pasteText()
        )
      }
    }
  )

  timeButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        utilityOutput.setText(
          new SimpleDateFormat(
            "dd-MM-yyyy HH:mm:ss"
          ).format(
            new Date()
          )
        )
      }
    }
  )

  tabs.addTab(
    "? UTILITIES",
    utilityPanel
  )

  // ==========================================================
  // FEATURE LIBRARY
  // ==========================================================

  val featurePanel =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  featurePanel.setBackground(BG)

  featurePanel.setBorder(
    new EmptyBorder(
      12,
      12,
      12,
      12
    )
  )

  val featureSearchField =
    makeField()

  val featureListModel =
    new DefaultListModel[String]()

  var featureFill = 0

  while (
    featureFill <
      featureLibrary.length
  ) {

    featureListModel.addElement(
      featureLibrary(
        featureFill
      )
    )

    featureFill += 1
  }

  val featureList =
    new JList[String](
      featureListModel
    )

  featureList.setBackground(
    PANEL3
  )

  featureList.setForeground(
    TEXT
  )

  featureList.setFont(
    new Font(
      "Segoe UI",
      Font.PLAIN,
      15
    )
  )

  val featureSearchBar =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  featureSearchBar.setBackground(BG)

  featureSearchBar.add(
    makeLabel(
      "SEARCH",
      14,
      true
    ),
    BorderLayout.WEST
  )

  featureSearchBar.add(
    featureSearchField,
    BorderLayout.CENTER
  )

  featurePanel.add(
    makeLabel(
      "? FEATURE LIBRARY ? " +
      featureLibrary.length,
      24,
      true
    ),
    BorderLayout.NORTH
  )

  featurePanel.add(
    makeScroll(
      featureList
    ),
    BorderLayout.CENTER
  )

  featurePanel.add(
    featureSearchBar,
    BorderLayout.SOUTH
  )

  featureSearchField.addKeyListener(
    new KeyAdapter {

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

        val search =
          featureSearchField
            .getText
            .toLowerCase

        featureListModel.clear()

        var i = 0

        while (
          i <
            featureLibrary.length
        ) {

          if (
            featureLibrary(i)
              .toLowerCase
              .contains(search)
          ) {

            featureListModel.addElement(
              featureLibrary(i)
            )
          }

          i += 1
        }
      }
    }
  )

  tabs.addTab(
    "? FEATURES",
    featurePanel
  )

  // ==========================================================
  // HISTORY PANEL
  // IMPORTANT:
  // No value/method name conflict here.
  // ==========================================================

  val historyPanel =
    new JPanel(
      new BorderLayout(
        8,
        8
      )
    )

  historyPanel.setBackground(BG)

  historyPanel.setBorder(
    new EmptyBorder(
      12,
      12,
      12,
      12
    )
  )

  val historyArea =
    makeArea()

  historyArea.setEditable(false)

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

  historyButtons.setBackground(BG)

  val refreshHistoryButton =
    makeButton(
      "REFRESH"
    )

  val exportHistoryButton =
    makeButton(
      "EXPORT"
    )

  val clearHistoryButton =
    makeButton(
      "CLEAR"
    )

  historyButtons.add(
    refreshHistoryButton
  )

  historyButtons.add(
    exportHistoryButton
  )

  historyButtons.add(
    clearHistoryButton
  )

  historyPanel.add(
    makeLabel(
      "? ACTIVITY HISTORY",
      25,
      true
    ),
    BorderLayout.NORTH
  )

  historyPanel.add(
    makeScroll(
      historyArea
    ),
    BorderLayout.CENTER
  )

  historyPanel.add(
    historyButtons,
    BorderLayout.SOUTH
  )

  // IMPORTANT:
  // This is a METHOD, not a value with the same name
  // as any JButton.
  def refreshHistoryView(): Unit = {

    if (
      activityHistory.isEmpty
    ) {

      historyArea.setText(
        "No activity yet."
      )

    } else {

      historyArea.setText(
        activityHistory
          .reverse
          .mkString(
            "\n"
          )
      )
    }
  }

  refreshHistoryButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        refreshHistoryView()
      }
    }
  )

  exportHistoryButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        saveTextFile(
          activityHistory
            .mkString("\n"),
          "ActivityHistory.txt"
        )
      }
    }
  )

  clearHistoryButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        activityHistory.clear()

        refreshHistoryView()
      }
    }
  )

  tabs.addTab(
    "? HISTORY",
    historyPanel
  )

  // ==========================================================
  // SETTINGS
  // ==========================================================

  val settingsPanel =
    new JPanel()

  settingsPanel.setBackground(BG)

  settingsPanel.setLayout(
    new BoxLayout(
      settingsPanel,
      BoxLayout.Y_AXIS
    )
  )

  settingsPanel.setBorder(
    new EmptyBorder(
      20,
      20,
      20,
      20
    )
  )

  val darkButton =
    makeButton(
      "DARK THEME"
    )

  val systemButton =
    makeButton(
      "SYSTEM THEME"
    )

  val fontPlusButton =
    makeButton(
      "FONT +"
    )

  val fontMinusButton =
    makeButton(
      "FONT -"
    )

  val fontResetButton =
    makeButton(
      "FONT RESET"
    )

  val aboutButton =
    makeButton(
      "ABOUT"
    )

  val featureCountButton =
    makeButton(
      "FEATURE COUNT"
    )

  settingsPanel.add(
    makeLabel(
      "? SETTINGS",
      25,
      true
    )
  )

  settingsPanel.add(
    Box.createVerticalStrut(
      15
    )
  )

  settingsPanel.add(
    darkButton
  )

  settingsPanel.add(
    Box.createVerticalStrut(
      8
    )
  )

  settingsPanel.add(
    systemButton
  )

  settingsPanel.add(
    Box.createVerticalStrut(
      8
    )
  )

  settingsPanel.add(
    fontPlusButton
  )

  settingsPanel.add(
    Box.createVerticalStrut(
      8
    )
  )

  settingsPanel.add(
    fontMinusButton
  )

  settingsPanel.add(
    Box.createVerticalStrut(
      8
    )
  )

  settingsPanel.add(
    fontResetButton
  )

  settingsPanel.add(
    Box.createVerticalStrut(
      8
    )
  )

  settingsPanel.add(
    featureCountButton
  )

  settingsPanel.add(
    Box.createVerticalStrut(
      8
    )
  )

  settingsPanel.add(
    aboutButton
  )

  darkButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        showInfo(
          "Theme",
          "Dark theme is already active."
        )
      }
    }
  )

  systemButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        try {

          UIManager.setLookAndFeel(
            UIManager
              .getSystemLookAndFeelClassName
          )

          SwingUtilities.updateComponentTreeUI(
            frame
          )

        } catch {

          case _: Throwable =>
        }
      }
    }
  )

  fontPlusButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        fontSizeValue =
          math.min(
            28,
            fontSizeValue + 2
          )

        showInfo(
          "Font",
          "Font size = " +
          fontSizeValue
        )
      }
    }
  )

  fontMinusButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        fontSizeValue =
          math.max(
            10,
            fontSizeValue - 2
          )

        showInfo(
          "Font",
          "Font size = " +
          fontSizeValue
        )
      }
    }
  )

  fontResetButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        fontSizeValue = 16

        showInfo(
          "Font",
          "Font reset to 16."
        )
      }
    }
  )

  featureCountButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        showInfo(
          "Features",
          "Registered features = " +
          featureLibrary.length
        )
      }
    }
  )

  aboutButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        showInfo(
          "About",
          "Scala Swing AI Learning Studio\n\n" +
          "Ultra Edition\n" +
          "Classroom + Coding + Debugging + Images + Projects + Utilities"
        )
      }
    }
  )

  tabs.addTab(
    "? SETTINGS",
    makeScroll(
      settingsPanel
    )
  )

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

  val bottomBar =
    new JPanel(
      new FlowLayout(
        FlowLayout.CENTER,
        7,
        5
      )
    )

  bottomBar.setBackground(
    new Color(
      10,
      12,
      17
    )
  )

  val stopwatchLabel =
    makeLabel(
      "STOPWATCH 00:00",
      13,
      true
    )

  val countdownLabel =
    makeLabel(
      "COUNTDOWN 00:00",
      13,
      true
    )

  val startStopwatchButton =
    makeButton(
      "START SW"
    )

  val stopStopwatchButton =
    makeButton(
      "STOP SW"
    )

  val resetStopwatchButton =
    makeButton(
      "RESET SW"
    )

  val startCountdownButton =
    makeButton(
      "START CD"
    )

  val resetCountdownButton =
    makeButton(
      "RESET CD"
    )

  bottomBar.add(
    stopwatchLabel
  )

  bottomBar.add(
    startStopwatchButton
  )

  bottomBar.add(
    stopStopwatchButton
  )

  bottomBar.add(
    resetStopwatchButton
  )

  bottomBar.add(
    countdownLabel
  )

  bottomBar.add(
    startCountdownButton
  )

  bottomBar.add(
    resetCountdownButton
  )

  startStopwatchButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        stopwatchRunning = true
      }
    }
  )

  stopStopwatchButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        stopwatchRunning = false
      }
    }
  )

  resetStopwatchButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        stopwatchSeconds = 0
        stopwatchRunning = false
      }
    }
  )

  startCountdownButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        val value =
          JOptionPane.showInputDialog(
            frame,
            "Countdown seconds:"
          )

        if (
          value != null
        ) {

          try {

            countdownSeconds =
              math.max(
                0,
                value.trim.toInt
              )

            countdownRunning =
              countdownSeconds > 0

          } catch {

            case _: Throwable =>

              showWarning(
                "Countdown",
                "Enter a valid whole number."
              )
          }
        }
      }
    }
  )

  resetCountdownButton.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        countdownSeconds = 0
        countdownRunning = false
      }
    }
  )

  val clockTimer =
    new javax.swing.Timer(
      1000,
      new ActionListener {

        def actionPerformed(
            e: ActionEvent
        ): Unit = {

          if (
            stopwatchRunning
          ) {

            stopwatchSeconds += 1
          }

          if (
            countdownRunning &&
            countdownSeconds > 0
          ) {

            countdownSeconds -= 1

            if (
              countdownSeconds == 0
            ) {

              countdownRunning = false

              showInfo(
                "Countdown",
                "Countdown finished."
              )
            }
          }

          val swMin =
            stopwatchSeconds / 60

          val swSec =
            stopwatchSeconds % 60

          stopwatchLabel.setText(
            "STOPWATCH " +
            f"$swMin%02d:$swSec%02d"
          )

          val cdMin =
            countdownSeconds / 60

          val cdSec =
            countdownSeconds % 60

          countdownLabel.setText(
            "COUNTDOWN " +
            f"$cdMin%02d:$cdSec%02d"
          )
        }
      }
    )

  clockTimer.start()

  root.add(
    tabs,
    BorderLayout.CENTER
  )

  root.add(
    bottomBar,
    BorderLayout.SOUTH
  )

  // ==========================================================
  // MENU BAR
  // ==========================================================

  val menuBar =
    new JMenuBar()

  val fileMenu =
    new JMenu(
      "File"
    )

  val classroomMenu =
    new JMenu(
      "Classroom"
    )

  val toolsMenu =
    new JMenu(
      "Tools"
    )

  val projectMenu =
    new JMenu(
      "Projects"
    )

  val exitMenuItem =
    new JMenuItem(
      "Exit"
    )

  val playMenuItem =
    new JMenuItem(
      "Play Lesson"
    )

  val askMenuItem =
    new JMenuItem(
      "Ask Teacher"
    )

  val codeMenuItem =
    new JMenuItem(
      "Code Lab"
    )

  val imageMenuItem =
    new JMenuItem(
      "Image Studio"
    )

  val featureMenuItem =
    new JMenuItem(
      "Features"
    )

  val historyMenuItem =
    new JMenuItem(
      "History"
    )

  val projectsMenuItem =
    new JMenuItem(
      "Project Builder"
    )

  fileMenu.add(
    exitMenuItem
  )

  classroomMenu.add(
    playMenuItem
  )

  classroomMenu.add(
    askMenuItem
  )

  toolsMenu.add(
    codeMenuItem
  )

  toolsMenu.add(
    imageMenuItem
  )

  toolsMenu.add(
    featureMenuItem
  )

  toolsMenu.add(
    historyMenuItem
  )

  projectMenu.add(
    projectsMenuItem
  )

  menuBar.add(
    fileMenu
  )

  menuBar.add(
    classroomMenu
  )

  menuBar.add(
    toolsMenu
  )

  menuBar.add(
    projectMenu
  )

  frame.setJMenuBar(
    menuBar
  )

  exitMenuItem.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        frame.dispose()
      }
    }
  )

  playMenuItem.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        tabs.setSelectedIndex(1)

        playCurrentLesson()
      }
    }
  )

  askMenuItem.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        tabs.setSelectedIndex(2)
      }
    }
  )

  codeMenuItem.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        tabs.setSelectedIndex(3)
      }
    }
  )

  imageMenuItem.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        tabs.setSelectedIndex(8)
      }
    }
  )

  featureMenuItem.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        tabs.setSelectedIndex(11)
      }
    }
  )

  historyMenuItem.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        tabs.setSelectedIndex(12)
      }
    }
  )

  projectsMenuItem.addActionListener(
    new ActionListener {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        tabs.setSelectedIndex(10)
      }
    }
  )

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

  val inputMap =
    root.getInputMap(
      JComponent.WHEN_IN_FOCUSED_WINDOW
    )

  val actionMap =
    root.getActionMap

  inputMap.put(
    KeyStroke.getKeyStroke(
      "control S"
    ),
    "saveCodeShortcut"
  )

  actionMap.put(
    "saveCodeShortcut",
    new AbstractAction {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        saveTextFile(
          codeEditor.getText,
          "ScalaCode.scala"
        )
      }
    }
  )

  inputMap.put(
    KeyStroke.getKeyStroke(
      "control L"
    ),
    "loadCodeShortcut"
  )

  actionMap.put(
    "loadCodeShortcut",
    new AbstractAction {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        loadTextFile(
          codeEditor
        )
      }
    }
  )

  inputMap.put(
    KeyStroke.getKeyStroke(
      "control K"
    ),
    "copyCodeShortcut"
  )

  actionMap.put(
    "copyCodeShortcut",
    new AbstractAction {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        copyText(
          codeEditor.getText
        )
      }
    }
  )

  inputMap.put(
    KeyStroke.getKeyStroke(
      "control Q"
    ),
    "askTeacherShortcut"
  )

  actionMap.put(
    "askTeacherShortcut",
    new AbstractAction {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        tabs.setSelectedIndex(2)
      }
    }
  )

  inputMap.put(
    KeyStroke.getKeyStroke(
      "ESCAPE"
    ),
    "stopSpeechShortcut"
  )

  actionMap.put(
    "stopSpeechShortcut",
    new AbstractAction {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        stopSpeech()
      }
    }
  )

  inputMap.put(
    KeyStroke.getKeyStroke(
      "F1"
    ),
    "helpShortcut"
  )

  actionMap.put(
    "helpShortcut",
    new AbstractAction {

      def actionPerformed(
          e: ActionEvent
      ): Unit = {

        showInfo(
          "Keyboard Shortcuts",
          "Ctrl+S = Save Code\n" +
          "Ctrl+L = Load Code\n" +
          "Ctrl+K = Copy Code\n" +
          "Ctrl+Q = Ask Teacher\n" +
          "Esc = Stop Voice\n" +
          "F1 = Help"
        )
      }
    }
  )

  // ==========================================================
  // INITIAL ACTIVITY
  // ==========================================================

  addActivity(
    "Application opened"
  )

  // IMPORTANT:
  // Call the method by its unique name.
  refreshHistoryView()

  frame.setContentPane(
    root
  )

  frame.setVisible(true)
}

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

SwingUtilities.invokeLater(
  new Runnable {

    def run(): Unit = {

      openLogin()
    }
  }
)