├── .gitignore ├── LICENSE ├── README.md ├── WORKSPACE └── src └── main ├── kotlin └── dev │ └── bbuck │ └── dragonconsole │ ├── BUILD │ ├── CommandProcessor.kt │ ├── DragonConsole.kt │ ├── demo │ ├── BUILD │ ├── Demo.kt │ ├── DemoProcessor.kt │ └── DragonConsoleFrame.kt │ ├── file │ ├── BUILD │ └── FileProcessor.kt │ ├── log │ ├── BUILD │ └── Debug.kt │ ├── text │ ├── Ansi.kt │ ├── BUILD │ ├── DocumentStyler.kt │ ├── InputString.kt │ ├── StoredInput.kt │ └── TextColor.kt │ └── ui │ ├── BUILD │ ├── InputController.kt │ ├── PromptLabel.kt │ └── PromptPanel.kt └── resources └── com └── eleet └── dragonconsole ├── BUILD ├── font ├── LICENSE └── dvsm.ttf └── resources ├── ansi ├── colors ├── input ├── l_console ├── l_font ├── logo_b └── logo_w /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .classpath 3 | .settings 4 | target 5 | *.iml 6 | *.ipr 7 | *.iws 8 | .idea 9 | *.class 10 | *~ 11 | .* 12 | !/.gitignore 13 | /bazel-* 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 Brandon Buck 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dragon Console 2 | 3 | ## Preview 4 | 5 | ![Dragon Console Image 1](http://content.screencast.com/users/izuriel/folders/Jing/media/72276c8d-7987-4622-ac41-c29b8995ffab/2010-11-23_0008.png) 6 | 7 | ## About 8 | 9 | DragonConsole v3.0.0 beta is finally finished and available for forking as it's 10 | been migrated to GitHub. Version 3 is the first to be released as an Open Source 11 | project and is a lightweight and useful Terminal Emulator for any Java 12 | application designed for any Operation System (with a JVM). 13 | 14 | ## Roadmap 15 | 16 | DragonConsole is undergoing some pretty massive changes in it's transition from 17 | "v3" to "v4." The largest of which is the migration from Java to Kotlin (which 18 | shouldn't affect your ability to use it in a Java program). 19 | 20 | The current largest changes: 21 | 22 | - Source has been ported (directly) to Kotlin, doing the best job to keep the 23 | exisiting interface intact (hence the current "3.1" version number). 24 | - The import path was changed from `com.eleet.dragonconsole` to 25 | `dev.bbuck.dragonconsole` since I don't own `com.eleet`. 26 | 27 | Upcoming larger changes: 28 | 29 | - Ground up rewrite in Kotlin, using Kotlin patterns 30 | - Saner logic (now that I've had 10 years to grows as an engineer since this 31 | was originally written) 32 | - Implementation of "builders" for the various color codes/input directives 33 | and other pieces to make integration of this library easier to read and 34 | understand 35 | 36 | ## Building 37 | 38 | DragonConsole uses [Bazel](https://bazel.build/) to build. If you don't already 39 | have a means to build your project you should consider this build system. If 40 | you want to get the demo up and running simple pull the project down: 41 | 42 | ``` 43 | $ git clone https://github.com/bbuck/dragonconsole 'DragonConsole' 44 | $ cd DragonConsole 45 | ``` 46 | 47 | Ensure you have Bazel installed, and run: 48 | 49 | ``` 50 | $ bazel build //src/main/kotlin/dragonconsole/demo:dragon_console 51 | $ bazel-build/src/main/kotlin/dragonconsole/demo/dragon_console 52 | ``` 53 | 54 | And that should be it. 55 | 56 | ## DragonConsole v3 Features 57 | 58 | - The ability to Color Text that is output to the Console with simple three 59 | character !DragonConsole Color Codes (DCCC). 60 | - A CommandProcessor to process all input given by the user. 61 | - Two methods of input. Inline, which allows the user to type directly in the 62 | Console (for a Console look and feel) or Separated input which uses an 63 | "Input Area" at the bottom of the Console for input. 64 | - FileProcessor for quick and easy reading of a plain text file and converting 65 | it into a String. 66 | - InputScript which allows the programmer to script input methods directly 67 | into Output sent to the console. There are four different types of input, 68 | Ranged, Protected Ranged, Infinite, and Protected Infinite. 69 | - ANSI Color Code support (must be enabled/disabled) with more ANSI Code Support 70 | on the way! 71 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 2 | 3 | rules_kotlin_version = "v1.5.0" 4 | 5 | rules_kotlin_sha = "12d22a3d9cbcf00f2e2d8f0683ba87d3823cb8c7f6837568dd7e48846e023307" 6 | 7 | http_archive( 8 | name = "io_bazel_rules_kotlin", 9 | sha256 = rules_kotlin_sha, 10 | type = "tgz", 11 | urls = [ 12 | "https://github.com/bazelbuild/rules_kotlin/releases/download/%s/rules_kotlin_release.tgz" % rules_kotlin_version, 13 | ], 14 | ) 15 | 16 | load("@io_bazel_rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories") 17 | 18 | kotlin_repositories() 19 | 20 | load("@io_bazel_rules_kotlin//kotlin:core.bzl", "kt_register_toolchains") 21 | 22 | kt_register_toolchains() 23 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/BUILD: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") 2 | 3 | package(default_visibility = ["//src/main:__subpackages__"]) 4 | 5 | kt_jvm_library( 6 | name = "dragon_console", 7 | srcs = [ 8 | "CommandProcessor.kt", 9 | "DragonConsole.kt", 10 | ], 11 | deps = [ 12 | "//src/main/kotlin/dev/bbuck/dragonconsole/file:file_processor", 13 | "//src/main/kotlin/dev/bbuck/dragonconsole/text:ansi", 14 | "//src/main/kotlin/dev/bbuck/dragonconsole/text:document_styler", 15 | "//src/main/kotlin/dev/bbuck/dragonconsole/text:text_color", 16 | "//src/main/kotlin/dev/bbuck/dragonconsole/ui:input_controller", 17 | "//src/main/kotlin/dev/bbuck/dragonconsole/ui:prompt_panel", 18 | ], 19 | ) 20 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/CommandProcessor.kt: -------------------------------------------------------------------------------- 1 | package dev.bbuck.dragonconsole 2 | 3 | import dev.bbuck.dragonconsole.file.readText 4 | import java.io.File 5 | 6 | public open class CommandProcessor { 7 | protected var console: DragonConsole? = null 8 | private set 9 | 10 | public fun install(console: DragonConsole) { 11 | this.console = console 12 | } 13 | 14 | public fun uninstall() { 15 | console = null 16 | } 17 | 18 | public open fun processCommand(input: String) = output(input + "\n") 19 | 20 | @Deprecated("Use the output(message) method instead") 21 | public fun outputToConsole(message: String) = output(message) 22 | 23 | public fun outputSystem(message: String) { 24 | console?.appendSystemMessage(message) 25 | } 26 | 27 | public fun outputError(message: String) { 28 | console?.appendErrorMessage(message) 29 | } 30 | 31 | public open fun output(message: String) { 32 | console?.append(message) 33 | } 34 | 35 | public fun readText(filePath: String): String = readText(filePath) 36 | 37 | public fun readText(file: File): String = readText(file) 38 | 39 | public fun convertToANSIColors(toConvert: String): String = 40 | console?.convertToANSIColors(toConvert) ?: toConvert 41 | 42 | public fun convertToDCColors(toConvert: String): String = 43 | console?.convertToDCColors(toConvert) ?: toConvert 44 | } 45 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/DragonConsole.kt: -------------------------------------------------------------------------------- 1 | package dev.bbuck.dragonconsole 2 | 3 | import dev.bbuck.dragonconsole.file.getConsoleFont as loadConsoleFont 4 | import dev.bbuck.dragonconsole.file.readDCResource 5 | import dev.bbuck.dragonconsole.text.ANSI 6 | import dev.bbuck.dragonconsole.text.TextColor 7 | import dev.bbuck.dragonconsole.text.addNewColor 8 | import dev.bbuck.dragonconsole.text.changeFont 9 | import dev.bbuck.dragonconsole.text.removeColor 10 | import dev.bbuck.dragonconsole.ui.InputController 11 | import dev.bbuck.dragonconsole.ui.PromptPanel 12 | import java.awt.BorderLayout 13 | import java.awt.Color 14 | import java.awt.Dimension 15 | import java.awt.Font 16 | import java.awt.Toolkit 17 | import java.awt.datatransfer.DataFlavor 18 | import java.awt.event.AdjustmentEvent 19 | import java.awt.event.AdjustmentListener 20 | import java.awt.event.KeyEvent 21 | import java.awt.event.KeyListener 22 | import javax.swing.JOptionPane 23 | import javax.swing.JOptionPane.showMessageDialog 24 | import javax.swing.JPanel 25 | import javax.swing.JScrollBar 26 | import javax.swing.JScrollPane 27 | import javax.swing.JTextArea 28 | import javax.swing.JTextPane 29 | import javax.swing.KeyStroke 30 | import javax.swing.SwingUtilities 31 | import javax.swing.event.CaretEvent 32 | import javax.swing.event.CaretListener 33 | import javax.swing.text.AbstractDocument 34 | import javax.swing.text.DefaultEditorKit 35 | import javax.swing.text.JTextComponent 36 | import javax.swing.text.SimpleAttributeSet 37 | import javax.swing.text.StyledDocument 38 | 39 | val VERSION = "3" 40 | val SUB_VERSION = "1" 41 | val BUG_FIX = "0" 42 | val VERSION_TAG = "" 43 | 44 | val DEFAULT_WIDTH = 725 45 | val DEFAULT_HEIGHT = 450 46 | 47 | val DEFAULT_BACKGROUND = Color.BLACK 48 | val DEFAULT_FOREGROUND = Color.GRAY.brighter() 49 | val DEFAULT_CARET = DEFAULT_FOREGROUND 50 | val DEFAULT_MAC_BACKGROUND = Color.WHITE 51 | val DEFAULT_MAC_FOREGROUND = Color.BLACK 52 | val DEFAULT_MAC_CARET = Color.BLACK 53 | 54 | val NUMBER_OF_PREVOIUS_ENTRIES = 10 55 | 56 | val OVERRIDE_KEY_BINDINGS = 57 | arrayOf( 58 | JTextComponent.KeyBinding( 59 | KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK), 60 | DefaultEditorKit.copyAction 61 | ), 62 | JTextComponent.KeyBinding( 63 | KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK), 64 | DefaultEditorKit.pasteAction 65 | ), 66 | JTextComponent.KeyBinding( 67 | KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.CTRL_DOWN_MASK), 68 | DefaultEditorKit.beepAction 69 | ), 70 | ) 71 | 72 | public class DragonConsole( 73 | private var cWidth: Int, 74 | private var cHeight: Int, 75 | private var useInlineInput: Boolean, 76 | private var printDefaultMessage: Boolean 77 | ) : JPanel(), KeyListener, CaretListener, AdjustmentListener { 78 | companion object { 79 | @JvmStatic val INTENSE_ORANGE = Color.ORANGE 80 | @JvmStatic val ORANGE = INTENSE_ORANGE.darker() 81 | @JvmStatic val INTENSE_PURPLE = Color(128, 0, 255) 82 | @JvmStatic val PURPLE = INTENSE_PURPLE.darker() 83 | @JvmStatic val INTENSE_GOLD = Color(241, 234, 139) 84 | @JvmStatic val GOLD = INTENSE_GOLD.darker() 85 | 86 | @JvmStatic 87 | public fun getVersion(): String { 88 | return "v$VERSION.$SUB_VERSION.$BUG_FIX$VERSION_TAG" 89 | } 90 | } 91 | 92 | var keepScrollBarMax = false 93 | var useANSIColorCodes = false 94 | 95 | var defaultColor = "xb" 96 | var systemColor = "cb" 97 | var errorColor = "rb" 98 | var inputColor = "xb" 99 | set(value) { 100 | field = value 101 | setInputAttribute() 102 | } 103 | private var currentStyle = defaultColor 104 | set(value) { 105 | val oldStyle = field 106 | var newStyle = "" 107 | if (value.length == 2) { 108 | if (value.contains("0")) { 109 | newStyle = defaultColor 110 | } else if (value.contains("-")) { 111 | if (!value.equals("--")) { 112 | if (value[0] == '-') { 113 | newStyle = "${oldStyle[0]}${value[1]}" 114 | } else { 115 | newStyle = "${value[0]}${oldStyle[1]}" 116 | } 117 | } 118 | } else { 119 | newStyle = value 120 | } 121 | 122 | val foreground = if (containsColorCode(newStyle[0])) newStyle[0] else oldStyle[0] 123 | val background = if (containsColorCode(newStyle[1])) newStyle[1] else oldStyle[1] 124 | 125 | field = "$foreground$background" 126 | } else { 127 | field = oldStyle 128 | } 129 | } 130 | private var ansiStyle: SimpleAttributeSet? = null 131 | 132 | var colorCodeChar = '&' 133 | 134 | var inputFieldNewLine = true 135 | var ignoreInput = false 136 | set(value) { 137 | field = value 138 | inputControl.ignoreInput = value 139 | } 140 | var inputCarryOver = true 141 | 142 | private val previousEntries = mutableListOf() 143 | private var currentPreviousEntry = 0 144 | 145 | private val textColors = mutableListOf() 146 | private val inputControl = InputController(null) 147 | private val consolePrompt = PromptPanel(">> ", defaultColor) 148 | 149 | private var currentConsoleFont = loadConsoleFont()?.deriveFont(Font.PLAIN, 14f) 150 | 151 | private var consolePane: JTextPane? = null 152 | private var consoleStyledDocument: StyledDocument? = null 153 | private var inputArea: JTextArea? = null 154 | private var consoleScrollPane: JScrollPane? = null 155 | private var commandProcessor: CommandProcessor? = null 156 | 157 | private var ignoreAdjustment = false 158 | private var isScrollBarAtMax = false 159 | 160 | init { 161 | setConsoleSize(cWidth, cHeight) 162 | 163 | val currentConsoleFont = currentConsoleFont 164 | if (currentConsoleFont != null) { 165 | consolePrompt.setPromptFont(currentConsoleFont) 166 | } 167 | 168 | if (useInlineInput) { 169 | consolePane = 170 | object : JTextPane() { 171 | override fun paste() { 172 | try { 173 | val pasteText = 174 | (Toolkit.getDefaultToolkit() 175 | .getSystemClipboard() 176 | .getData(DataFlavor.stringFlavor)) as 177 | String 178 | getDocument().insertString(getCaretPosition(), pasteText, null) 179 | } catch (ex: Exception) { 180 | showMessageDialog( 181 | this, 182 | "Error #0001\nFailed to paste text to the document!\n${ex.message}", 183 | "Error Caught!", 184 | JOptionPane.ERROR_MESSAGE 185 | ) 186 | } 187 | } 188 | } 189 | 190 | consolePane?.addKeyListener(this) 191 | consolePane?.addCaretListener(this) 192 | } else { 193 | consolePane = JTextPane() 194 | consolePane?.setEditable(false) 195 | } 196 | 197 | val consolePane = consolePane 198 | if (consolePane == null) { 199 | throw IllegalStateException("No text pane was created, this should be impossible") 200 | } 201 | 202 | consolePane.setBackground(DEFAULT_BACKGROUND) 203 | consolePane.setForeground(DEFAULT_FOREGROUND) 204 | consolePane.setCaretColor(DEFAULT_CARET) 205 | consolePane.setFont(currentConsoleFont) 206 | consolePane.setBorder(null) 207 | 208 | val keymap = consolePane.getKeymap() 209 | JTextComponent.loadKeymap(keymap, OVERRIDE_KEY_BINDINGS, consolePane.getActions()) 210 | 211 | inputControl.installConsole(consolePane) 212 | inputControl.consoleInputMethod = useInlineInput 213 | 214 | consoleStyledDocument = consolePane.styledDocument 215 | if (useInlineInput) { 216 | (consoleStyledDocument as AbstractDocument).documentFilter = inputControl 217 | } 218 | 219 | inputArea = JTextArea() 220 | val inputArea = inputArea 221 | if (inputArea == null) { 222 | throw IllegalStateException("inputArea is null, this is impossible") 223 | } 224 | inputArea.setBackground(DEFAULT_BACKGROUND) 225 | inputArea.setForeground(DEFAULT_FOREGROUND) 226 | inputArea.setCaretColor(DEFAULT_CARET) 227 | inputArea.setWrapStyleWord(true) 228 | inputArea.setLineWrap(true) 229 | inputArea.setFont(currentConsoleFont) 230 | inputArea.setBorder(null) 231 | inputArea.addKeyListener(this) 232 | 233 | consoleScrollPane = JScrollPane(consolePane) 234 | consoleScrollPane?.setBorder(null) 235 | consoleScrollPane?.getVerticalScrollBar()?.addAdjustmentListener(this) 236 | 237 | val inputPanel = JPanel(BorderLayout()) 238 | inputPanel.add(consolePrompt, BorderLayout.WEST) 239 | inputPanel.add(inputArea, BorderLayout.CENTER) 240 | 241 | val splitPane = JPanel(BorderLayout()) 242 | splitPane.add(consoleScrollPane, BorderLayout.CENTER) 243 | splitPane.add(inputPanel, BorderLayout.SOUTH) 244 | 245 | setLayout(BorderLayout()) 246 | if (useInlineInput) { 247 | add(consoleScrollPane, BorderLayout.CENTER) 248 | } else { 249 | add(splitPane, BorderLayout.CENTER) 250 | } 251 | 252 | setOutputStyles() 253 | setDefaultStyle() 254 | } 255 | 256 | constructor() : this(DEFAULT_WIDTH, DEFAULT_HEIGHT, true, true) 257 | constructor(useInlineInput: Boolean) : this(DEFAULT_WIDTH, DEFAULT_HEIGHT, useInlineInput, true) 258 | constructor( 259 | useInlineInput: Boolean, 260 | printDefaultMessage: Boolean 261 | ) : this(DEFAULT_WIDTH, DEFAULT_HEIGHT, useInlineInput, printDefaultMessage) 262 | constructor(width: Int, height: Int) : this(width, height, true, true) 263 | constructor( 264 | width: Int, 265 | height: Int, 266 | useInlineInput: Boolean 267 | ) : this(width, height, useInlineInput, true) 268 | 269 | public fun setConsoleSize(dimension: Dimension) { 270 | super.setMaximumSize(dimension) 271 | super.setMinimumSize(dimension) 272 | super.setPreferredSize(dimension) 273 | } 274 | 275 | public fun setConsoleSize(width: Int, height: Int) = setConsoleSize(Dimension(width, height)) 276 | 277 | public fun addTextColor(code: Char, color: Color) { 278 | val newColor = TextColor(code, color) 279 | textColors.add(newColor) 280 | if (!useInlineInput) { 281 | consolePrompt.addColor(newColor) 282 | } 283 | 284 | val consoleStyledDocument = consoleStyledDocument 285 | if (consoleStyledDocument == null) { 286 | return 287 | } 288 | 289 | this.consoleStyledDocument = addNewColor(consoleStyledDocument, newColor, textColors) 290 | } 291 | 292 | public fun removeTextColor(code: Char): TextColor? { 293 | val consoleStyledDocument = consoleStyledDocument 294 | if (consoleStyledDocument == null) { 295 | return null 296 | } 297 | 298 | val toRemove = textColors.find { it.charCode == code } 299 | if (toRemove == null) { 300 | return null 301 | } 302 | 303 | textColors.remove(toRemove) 304 | removeColor(consoleStyledDocument, toRemove, textColors) 305 | if (!useInlineInput) { 306 | consolePrompt.removeColor(toRemove) 307 | } 308 | 309 | return toRemove 310 | } 311 | 312 | public fun removeTextColor(color: Color): TextColor? { 313 | val consoleStyledDocument = consoleStyledDocument 314 | if (consoleStyledDocument == null) { 315 | return null 316 | } 317 | 318 | val toRemove = textColors.find { it.color == color } 319 | if (toRemove == null) { 320 | return null 321 | } 322 | 323 | textColors.remove(toRemove) 324 | removeColor(consoleStyledDocument, toRemove, textColors) 325 | if (!useInlineInput) { 326 | consolePrompt.removeColor(toRemove) 327 | } 328 | 329 | return toRemove 330 | } 331 | 332 | public fun updateTextColor(code: Char, newColor: Color) { 333 | val removed = removeTextColor(code) 334 | 335 | if (removed == null) { 336 | return 337 | } 338 | 339 | addTextColor(code, newColor) 340 | } 341 | 342 | public fun updateTextColor(color: Color, newCode: Char) { 343 | val removed = removeTextColor(color) 344 | 345 | if (removed == null) { 346 | return 347 | } 348 | 349 | addTextColor(newCode, color) 350 | } 351 | 352 | public fun clearTextColors() { 353 | val consoleStyledDocument = consoleStyledDocument 354 | if (consoleStyledDocument == null) { 355 | return 356 | } 357 | 358 | textColors.forEach { color -> removeColor(consoleStyledDocument, color, textColors) } 359 | textColors.clear() 360 | if (!useInlineInput) { 361 | consolePrompt.clearColors() 362 | } 363 | } 364 | 365 | public fun setDefaultStyle() { 366 | consolePane?.setBackground(DEFAULT_BACKGROUND) 367 | consolePane?.setCaretColor(DEFAULT_CARET) 368 | consolePane?.setForeground(DEFAULT_FOREGROUND) 369 | inputArea?.setBackground(DEFAULT_BACKGROUND) 370 | inputArea?.setCaretColor(DEFAULT_CARET) 371 | inputArea?.setForeground(DEFAULT_FOREGROUND) 372 | consolePrompt.setPromptForeground(DEFAULT_FOREGROUND) 373 | consolePrompt.setBackground(DEFAULT_BACKGROUND) 374 | 375 | defaultColor = "xb" 376 | systemColor = "cb" 377 | errorColor = "rb" 378 | inputColor = "xb" 379 | 380 | if (useInlineInput) { 381 | consolePrompt.defaultColor = defaultColor 382 | } 383 | clearConsole() 384 | printDefault() 385 | } 386 | 387 | public fun setMacStyle() { 388 | consolePane?.setBackground(DEFAULT_MAC_BACKGROUND) 389 | consolePane?.setCaretColor(DEFAULT_MAC_CARET) 390 | consolePane?.setForeground(DEFAULT_MAC_FOREGROUND) 391 | inputArea?.setBackground(DEFAULT_MAC_BACKGROUND) 392 | inputArea?.setCaretColor(DEFAULT_MAC_CARET) 393 | inputArea?.setForeground(DEFAULT_MAC_FOREGROUND) 394 | consolePrompt.setPromptForeground(DEFAULT_MAC_FOREGROUND) 395 | consolePrompt.setBackground(DEFAULT_MAC_BACKGROUND) 396 | 397 | defaultColor = "bw" 398 | systemColor = "ow" 399 | errorColor = "rw" 400 | inputColor = "bw" 401 | 402 | if (useInlineInput) { 403 | consolePrompt.defaultColor = defaultColor 404 | } 405 | clearConsole() 406 | printDefault() 407 | } 408 | 409 | public fun clearConsole(): Unit = inputControl.clearText() 410 | 411 | @Deprecated("Language was changed from display to append", ReplaceWith("appendSystemMessage")) 412 | public fun displaySystemMessage(message: String) { 413 | appendSystemMessage(message) 414 | } 415 | 416 | public fun appendSystemMessage(message: String) { 417 | print(message, systemColor) 418 | } 419 | 420 | @Deprecated("Language was changed from display to append", ReplaceWith("appendErrorMessage")) 421 | public fun displayErrorMessage(message: String) { 422 | print(message, errorColor) 423 | } 424 | 425 | public fun appendErrorMessage(message: String) { 426 | print(message, errorColor) 427 | } 428 | 429 | public fun append(output: String) { 430 | if (!ignoreInput && inputCarryOver && inputControl.isReceivingInput) { 431 | inputControl.storeInput() 432 | } 433 | 434 | var hasInput = false 435 | val processed = StringBuilder() 436 | 437 | var i = 0 438 | while (i < output.length) { 439 | if (output[i] == colorCodeChar) { 440 | if (i + 1 < output.length && output[i + 1] == colorCodeChar) { 441 | processed.append(colorCodeChar) 442 | i += 1 443 | } else if (i + 2 < output.length) { 444 | print(processed.toString()) 445 | processed.clear() 446 | 447 | currentStyle = output.substring(i + 1, i + 3) 448 | i += 2 449 | } 450 | } else if (output[i] == '\u001b') { 451 | if (output.indexOf('m', i) < output.length) { 452 | print(processed.toString()) 453 | processed.clear() 454 | 455 | val consoleStyledDocument = consoleStyledDocument 456 | if (consoleStyledDocument != null) { 457 | ansiStyle = 458 | ANSI.getANSIAttribute( 459 | ansiStyle, 460 | output.substring(i, output.indexOf('m', i) + 1), 461 | consoleStyledDocument.getStyle(defaultColor) 462 | ) 463 | } 464 | i = output.indexOf('m', i) 465 | } 466 | } else if (output[i] == '%' && !ignoreInput) { 467 | if (i + 1 < output.length && output[i + 1] == '%') { 468 | processed.append('%') 469 | i += 1 470 | } else if (output.indexOf(';', i) > i) { 471 | if (output[i + 1] == 'i') { 472 | hasInput = true 473 | val inputCommand = output.substring(i, output.indexOf(';', i) + 1) 474 | 475 | if (inputControl.setInputStyle(inputCommand)) { 476 | print(processed.toString()) 477 | processed.clear() 478 | 479 | inputControl.setRangeStart(consoleStyledDocument?.length ?: 0) 480 | print(inputControl.getInputRangeString(), defaultColor) 481 | } else { 482 | i = output.length 483 | print(processed.toString()) 484 | processed.clear() 485 | inputControl.setRangeStart(consoleStyledDocument?.length ?: 0) 486 | } 487 | 488 | i = output.indexOf(';', i) 489 | } 490 | } else { 491 | processed.append(output[i]) 492 | } 493 | } else { 494 | processed.append(output[i]) 495 | } 496 | 497 | i += 1 498 | } 499 | 500 | print(processed.toString()) 501 | 502 | if (!hasInput) { 503 | inputControl.setBasicInput(consoleStyledDocument?.getLength() ?: 0) 504 | } 505 | 506 | setConsoleCaretPosition() 507 | } 508 | 509 | @Deprecated("Language was changed from display to append", ReplaceWith("append")) 510 | public fun displayString(toDisplay: String) { 511 | append(toDisplay) 512 | } 513 | 514 | public fun appendWithoutProcessing(output: String) { 515 | print(output, defaultColor) 516 | inputControl.setBasicInput(consoleStyledDocument?.length ?: 0) 517 | } 518 | 519 | public fun setProtectedCharacter(protectedChar: Char) { 520 | inputControl.setProtectedChar(protectedChar) 521 | } 522 | 523 | public fun setInputFocus() { 524 | if (useInlineInput) { 525 | return 526 | } 527 | 528 | inputArea?.requestFocusInWindow() 529 | } 530 | 531 | public fun isUseANSIColorCodes(): Boolean = useANSIColorCodes 532 | 533 | public fun setPrompt(newPrompt: String) { 534 | consolePrompt.setPrompt(newPrompt) 535 | } 536 | 537 | public fun setCommandProcessor(newProcessor: CommandProcessor) { 538 | val commandProcessor = commandProcessor 539 | if (commandProcessor != null) { 540 | commandProcessor.uninstall() 541 | } 542 | 543 | this.commandProcessor = newProcessor 544 | this.commandProcessor?.install(this) 545 | } 546 | 547 | public fun setConsoleFont(newConsoleFont: Font) { 548 | currentConsoleFont = newConsoleFont 549 | setOutputStyles() 550 | consolePane?.setFont(newConsoleFont) 551 | inputArea?.setFont(newConsoleFont) 552 | consolePrompt.setPromptFont(newConsoleFont) 553 | val consoleStyledDocument = consoleStyledDocument 554 | if (consoleStyledDocument != null) { 555 | changeFont(consoleStyledDocument, newConsoleFont) 556 | } 557 | } 558 | 559 | public fun convertToANSIColors(toConvert: String): String = 560 | ANSI.convertDCtoANSIColors(toConvert, textColors, colorCodeChar) 561 | 562 | public fun convertToDCColors(toConvert: String): String = 563 | ANSI.convertANSIToDCColors(toConvert, textColors, colorCodeChar, defaultColor) 564 | 565 | override public fun keyTyped(event: KeyEvent) { 566 | // empty 567 | } 568 | override public fun keyReleased(event: KeyEvent) { 569 | // empty 570 | } 571 | 572 | override public fun keyPressed(event: KeyEvent) { 573 | if (!useInlineInput) { 574 | if (keepScrollBarMax || isScrollBarAtMax) { 575 | ignoreAdjustment = true 576 | setScrollBarMax() 577 | } 578 | } 579 | 580 | when (event.getKeyCode()) { 581 | KeyEvent.VK_TAB -> event.consume() 582 | KeyEvent.VK_ENTER -> { 583 | if (ignoreInput) { 584 | return 585 | } 586 | 587 | if (useInlineInput) { 588 | event.consume() 589 | val isProtected = inputControl.isProtected() 590 | val input = inputControl.getInput() 591 | 592 | val commandProcessor = commandProcessor 593 | if (commandProcessor != null) { 594 | commandProcessor.processCommand(input) 595 | } else { 596 | appendWithoutProcessing(input) 597 | } 598 | 599 | if (!isProtected) { 600 | addPreviousEntry(input) 601 | } 602 | } else { 603 | if (inputFieldNewLine || event.isShiftDown()) { 604 | inputArea?.append("\n") 605 | 606 | return 607 | } 608 | 609 | event.consume() 610 | val input = inputArea?.getText() ?: "" 611 | val commandProcessor = commandProcessor 612 | if (commandProcessor != null) { 613 | commandProcessor.processCommand(input) 614 | } else { 615 | appendWithoutProcessing(input) 616 | } 617 | 618 | addPreviousEntry(input) 619 | } 620 | } 621 | KeyEvent.VK_RIGHT -> { 622 | if (!event.isShiftDown()) { 623 | return 624 | } 625 | 626 | event.consume() 627 | 628 | if (!useInlineInput || 629 | (inputControl.isReceivingInput && inputControl.isInfiniteInput()) 630 | ) { 631 | currentPreviousEntry -= 1 632 | if (currentPreviousEntry < 0) { 633 | currentPreviousEntry = previousEntries.size - 1 634 | } 635 | 636 | setPreviousEntryText() 637 | } 638 | } 639 | KeyEvent.VK_LEFT -> { 640 | if (!event.isShiftDown()) { 641 | return 642 | } 643 | 644 | event.consume() 645 | 646 | if (!useInlineInput || 647 | (inputControl.isReceivingInput && inputControl.isInfiniteInput()) 648 | ) { 649 | currentPreviousEntry += 1 650 | if (currentPreviousEntry >= previousEntries.size) { 651 | currentPreviousEntry = 0 652 | } 653 | 654 | setPreviousEntryText() 655 | } 656 | } 657 | } 658 | } 659 | 660 | public override fun caretUpdate(event: CaretEvent) { 661 | if (ignoreInput) { 662 | return 663 | } 664 | 665 | val location = event.dot 666 | 667 | if (!(inputControl.isReceivingInput && location == event.mark)) { 668 | return 669 | } 670 | 671 | val consolePane = consolePane 672 | if (consolePane == null) { 673 | return 674 | } 675 | 676 | if (location < inputControl.getInputRangeStart()) { 677 | consolePane.caretPosition = inputControl.getInputRangeStart() 678 | 679 | return 680 | } 681 | 682 | if (!inputControl.isInfiniteInput() && location > inputControl.getInputRangeEnd()) { 683 | consolePane.caretPosition = inputControl.getInputRangeEnd() 684 | 685 | return 686 | } 687 | } 688 | 689 | public override fun adjustmentValueChanged(event: AdjustmentEvent) { 690 | if (event.source !is JScrollBar) { 691 | return 692 | } 693 | 694 | if (ignoreAdjustment) { 695 | ignoreAdjustment = false 696 | 697 | return 698 | } 699 | 700 | val scrollBar = event.source as JScrollBar 701 | val value = event.value 702 | val maxValue = scrollBar.maximum - scrollBar.model.extent 703 | 704 | isScrollBarAtMax = value == maxValue 705 | } 706 | 707 | protected fun print(output: String, style: String) { 708 | ignoreAdjustment = true 709 | 710 | val actualOutput = 711 | if (useInlineInput) { 712 | "${inputControl.getBypassPrefix()}$output" 713 | } else { 714 | output 715 | } 716 | 717 | try { 718 | consoleStyledDocument?.insertString( 719 | (consoleStyledDocument?.length ?: 0), 720 | actualOutput, 721 | consoleStyledDocument?.getStyle(style) 722 | ) 723 | } catch (ex: Exception) { 724 | showMessageDialog( 725 | this, 726 | "Error #0006\nFailed to print the text with the given style!\n${ex.message}", 727 | "Error Caught!", 728 | JOptionPane.ERROR_MESSAGE 729 | ) 730 | } 731 | } 732 | 733 | protected fun print(output: String, attributeSet: SimpleAttributeSet) { 734 | ignoreAdjustment = true 735 | 736 | val actualOutput = 737 | if (useInlineInput) { 738 | "${inputControl.getBypassPrefix()}$output" 739 | } else { 740 | output 741 | } 742 | 743 | try { 744 | consoleStyledDocument?.insertString( 745 | (consoleStyledDocument?.length ?: 0), 746 | actualOutput, 747 | attributeSet 748 | ) 749 | } catch (ex: Exception) { 750 | showMessageDialog( 751 | this, 752 | "Error #0007\nFailed to print the text with the ANSI style!\n${ex.message}", 753 | "Error Caught!", 754 | JOptionPane.ERROR_MESSAGE 755 | ) 756 | } 757 | } 758 | 759 | protected fun print(output: String) { 760 | if (output.isEmpty()) { 761 | return 762 | } 763 | 764 | val ansiStyle = ansiStyle 765 | if (useANSIColorCodes && ansiStyle != null) { 766 | print(output, ansiStyle) 767 | } else { 768 | print(output, currentStyle) 769 | } 770 | } 771 | 772 | protected fun setScrollBarMax() { 773 | val consoleScrollPane = consoleScrollPane 774 | if (consoleScrollPane == null) { 775 | return 776 | } 777 | 778 | if (!isScrollBarAtMax) { 779 | return 780 | } 781 | 782 | val verticalBar = consoleScrollPane.verticalScrollBar 783 | val console = this 784 | 785 | SwingUtilities.invokeLater { 786 | try { 787 | if (verticalBar.isVisible()) { 788 | verticalBar.setValue(verticalBar.maximum - verticalBar.model.extent) 789 | } 790 | 791 | console.repaint() 792 | } catch (ex: Exception) { 793 | showMessageDialog( 794 | console, 795 | "Error #0005\nFailed to set the JScrollBar to max value!\n${ex.message}", 796 | "Error Caught!", 797 | JOptionPane.ERROR_MESSAGE 798 | ) 799 | } 800 | } 801 | } 802 | 803 | private fun fillConsoleColors() { 804 | addTextColor('r', ANSI.INTENSE_RED) 805 | addTextColor('R', ANSI.RED) 806 | addTextColor('l', ANSI.INTENSE_BLUE) 807 | addTextColor('L', ANSI.BLUE) 808 | addTextColor('g', ANSI.INTENSE_GREEN) 809 | addTextColor('G', ANSI.GREEN) 810 | addTextColor('y', ANSI.INTENSE_YELLOW) 811 | addTextColor('Y', ANSI.YELLOW) 812 | addTextColor('x', ANSI.WHITE) 813 | addTextColor('X', ANSI.INTENSE_BLACK) 814 | addTextColor('c', ANSI.INTENSE_CYAN) 815 | addTextColor('C', ANSI.CYAN) 816 | addTextColor('m', ANSI.INTENSE_MAGENTA) 817 | addTextColor('M', ANSI.MAGENTA) 818 | 819 | addTextColor('o', INTENSE_ORANGE) 820 | addTextColor('O', ORANGE) 821 | addTextColor('p', INTENSE_PURPLE) 822 | addTextColor('P', PURPLE) 823 | addTextColor('d', INTENSE_GOLD) 824 | addTextColor('D', GOLD) 825 | 826 | addTextColor('b', ANSI.BLACK) 827 | addTextColor('w', ANSI.INTENSE_WHITE) 828 | } 829 | 830 | private fun getStyleColorFromCode(code: Char): Color { 831 | val found = textColors.find { it.charCode == code } 832 | if (found != null) { 833 | return found.color 834 | } 835 | 836 | return Color.WHITE 837 | } 838 | 839 | private fun setInputAttribute() { 840 | val consoleStyledDocument = consoleStyledDocument 841 | if (consoleStyledDocument == null) { 842 | return 843 | } 844 | 845 | inputControl.inputAttributeSet = consoleStyledDocument.getStyle(inputColor) 846 | if (!useInlineInput) { 847 | inputArea?.setForeground(getStyleColorFromCode(inputColor[0])) 848 | inputArea?.setBackground(getStyleColorFromCode(inputColor[1])) 849 | } 850 | } 851 | 852 | private fun setOutputStyles() { 853 | fillConsoleColors() 854 | setInputAttribute() 855 | } 856 | 857 | private fun printDefault() { 858 | if (!printDefaultMessage) { 859 | return 860 | } 861 | 862 | var color = "b" 863 | // TOOD(bbuck) make less terrible 864 | if (consolePane?.getBackground()?.equals(Color.WHITE) == true) { 865 | color = "w" 866 | } 867 | 868 | try { 869 | append(readDCResource("logo_$color")) 870 | } catch (ex: Exception) { 871 | showMessageDialog( 872 | this, 873 | "Error #0002\nFailed to read teh logo from the jar!\n${ex.message}", 874 | "Error Caught!", 875 | JOptionPane.ERROR_MESSAGE 876 | ) 877 | } 878 | } 879 | 880 | private fun addPreviousEntry(entry: String) { 881 | previousEntries.add(entry) 882 | if (previousEntries.size > NUMBER_OF_PREVOIUS_ENTRIES) { 883 | previousEntries.removeAt(0) 884 | } 885 | currentPreviousEntry = previousEntries.size 886 | } 887 | 888 | private fun setPreviousEntryText() { 889 | if (currentPreviousEntry < 0 || currentPreviousEntry >= previousEntries.size) { 890 | return 891 | } 892 | 893 | val entry = previousEntries[currentPreviousEntry] 894 | if (useInlineInput) { 895 | if (inputControl.isReceivingInput && inputControl.isInfiniteInput()) { 896 | inputControl.setInput(entry) 897 | } 898 | } else { 899 | inputArea?.setText(entry) 900 | if (keepScrollBarMax || isScrollBarAtMax) { 901 | ignoreAdjustment = true 902 | setScrollBarMax() 903 | } 904 | } 905 | } 906 | 907 | private fun containsColorCode(code: Char): Boolean { 908 | val color = textColors.find { it.charCode == code } 909 | 910 | return color != null 911 | } 912 | 913 | private fun setConsoleCaretPosition() { 914 | val caretLocation = inputControl.getInputRangeStart() 915 | if (ignoreInput) { 916 | consolePane?.caretPosition = 0 917 | } else { 918 | if (caretLocation > -1) { 919 | consolePane?.caretPosition = caretLocation 920 | } else { 921 | consolePane?.caretPosition = consoleStyledDocument?.length ?: 0 922 | } 923 | 924 | if (inputCarryOver && inputControl.hasStoredInput()) { 925 | inputControl.restoreInput() 926 | } 927 | 928 | if (keepScrollBarMax || isScrollBarAtMax) { 929 | setScrollBarMax() 930 | } 931 | } 932 | } 933 | } 934 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/demo/BUILD: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") 2 | 3 | package(default_visibility = ["//src/main:__subpackages__"]) 4 | 5 | kt_jvm_library( 6 | name = "dragon_console_frame", 7 | srcs = ["DragonConsoleFrame.kt"], 8 | deps = [ 9 | "//src/main/kotlin/dev/bbuck/dragonconsole:dragon_console", 10 | ], 11 | ) 12 | 13 | kt_jvm_library( 14 | name = "demo_processor", 15 | srcs = ["DemoProcessor.kt"], 16 | deps = [ 17 | "//src/main/kotlin/dev/bbuck/dragonconsole:dragon_console", 18 | "//src/main/kotlin/dev/bbuck/dragonconsole/file:file_processor", 19 | ], 20 | ) 21 | 22 | kt_jvm_library( 23 | name = "demo", 24 | srcs = ["Demo.kt"], 25 | deps = [ 26 | ":demo_processor", 27 | ":dragon_console_frame", 28 | ], 29 | ) 30 | 31 | java_binary( 32 | name = "dragon_console_demo", 33 | main_class = "dev.bbuck.dragonconsole.demo.Demo", 34 | resources = [ 35 | "//src/main/kotlin/dev/bbuck/dragonconsole/text:ansi", 36 | "//src/main/resources/com/eleet/dragonconsole:resources/ansi", 37 | "//src/main/resources/com/eleet/dragonconsole:resources/colors", 38 | "//src/main/resources/com/eleet/dragonconsole:resources/input", 39 | "//src/main/resources/com/eleet/dragonconsole:resources/l_console", 40 | "//src/main/resources/com/eleet/dragonconsole:resources/l_font", 41 | "//src/main/resources/com/eleet/dragonconsole:resources/logo_b", 42 | "//src/main/resources/com/eleet/dragonconsole:resources/logo_w", 43 | ], 44 | runtime_deps = [ 45 | ":demo", 46 | ], 47 | ) 48 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/demo/Demo.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("Demo") 2 | 3 | package dev.bbuck.dragonconsole.demo 4 | 5 | import javax.swing.SwingUtilities 6 | import javax.swing.UIManager 7 | 8 | fun main() { 9 | SwingUtilities.invokeLater { 10 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()) 11 | val frame = DragonConsoleFrame() 12 | frame.console.setCommandProcessor(DemoProcessor()) 13 | frame.console.append("&ob>> ") 14 | frame.setVisible(true) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/demo/DemoProcessor.kt: -------------------------------------------------------------------------------- 1 | package dev.bbuck.dragonconsole.demo 2 | 3 | import dev.bbuck.dragonconsole.CommandProcessor 4 | import dev.bbuck.dragonconsole.DragonConsole 5 | import dev.bbuck.dragonconsole.file.readDCResource 6 | import kotlin.system.exitProcess 7 | 8 | val VALID_INFO_SUBCOMMANDS = listOf("colors", "ansi", "input") 9 | val VALID_LICENSE_TARGETS = 10 | mapOf( 11 | "font" to "l_font", 12 | "dragonconsole" to "l_console", 13 | ) 14 | 15 | val HELP_STRING = 16 | """ 17 | 18 | &c-== &X-Dragon&x-Console&c- ${DragonConsole.getVersion()} =============== 19 | &w-INFO &o-View information on certain topics. 20 | &w- EX: INFO COLORS 21 | OPTS: COLORS, ANSI, or INPUT 22 | 23 | LICENSE &o-View the License for DragonConsole or third party 24 | components. 25 | &w- EX: LICENSE DRAGONCONSOLE 26 | OPTS: DRAGONCONSOLE or FONT 27 | 28 | ANSI &o-Enable or Disable ANSI codes (this will also 29 | toggle DCCCs 30 | &w- EX ANSI ON 31 | OPTS: ON or OFF 32 | 33 | DEMO &o- Demo the difference input methods (ranged and 34 | infinite) as well as protected and unprotected 35 | &w- EX: DEMO INPUT RANGED 36 | OPTS: INPUT [RANGED|INFINITE] [PROTECTED] 37 | 38 | EXIT &o-Exit the console demo application. 39 | 40 | &w-HELP &o-Show this help screen. 41 | &c-========================================""" 42 | 43 | public class DemoProcessor : CommandProcessor() { 44 | var activelyDemoingInput = false 45 | 46 | override fun processCommand(input: String) { 47 | if (activelyDemoingInput) { 48 | output("\n\n&c-Your input:&00 ${input}") 49 | activelyDemoingInput = false 50 | output("\n\n&ob>>&00 ") 51 | 52 | return 53 | } 54 | 55 | val cmdParts = input.lowercase().split(' ') 56 | when { 57 | cmdParts.isEmpty() -> 58 | outputSystem( 59 | "\n\nYou must enter a command! Valid commands are INFO, LICENSE, DEMO, ANSI, and EXIT" 60 | ) 61 | cmdParts.first() == "info" -> { 62 | if (cmdParts.size > 1) { 63 | val fileName = cmdParts[1] 64 | if (fileName in VALID_INFO_SUBCOMMANDS) { 65 | output("\n\n${readDCResource(fileName)}") 66 | } else { 67 | outputSystem("\n\nNot a valid argument to INFO, type 'INFO' for help.") 68 | } 69 | } else { 70 | outputSystem("\n\nValid arguments for INFO are: COLORS, ANSI, or INPUT") 71 | } 72 | } 73 | cmdParts.first() == "license" -> { 74 | if (cmdParts.size > 1) { 75 | val licenseTarget = cmdParts[1] 76 | val licenseFile = VALID_LICENSE_TARGETS.get(licenseTarget) 77 | if (licenseFile != null) { 78 | output("\n\n${readDCResource(licenseFile)}") 79 | } else { 80 | outputSystem( 81 | "\n\nNot a valid argument for LICENSE, type \"LICENSE\" for help." 82 | ) 83 | } 84 | } else { 85 | outputSystem("\n\nValid arguments for LICENSE are FONT and DRAGONCONSOLE.") 86 | } 87 | } 88 | cmdParts.first() == "ansi" -> { 89 | if (cmdParts.size > 1) { 90 | when (cmdParts[1]) { 91 | "on" -> { 92 | console?.useANSIColorCodes = true 93 | outputSystem("\n\nANSI Color Codes are now on.") 94 | } 95 | "off" -> { 96 | console?.useANSIColorCodes = false 97 | outputSystem("\n\nANSI Color Codes are now off.") 98 | } 99 | else -> 100 | outputSystem( 101 | "\n\nInvalid argument for ANSI, type \"ANSI\" for help." 102 | ) 103 | } 104 | } else { 105 | outputSystem("\n\nValid arguments for ANSI are ON and OFF.") 106 | } 107 | } 108 | cmdParts.first() == "demo" -> { 109 | val demoOption = cmdParts.getOrNull(1) 110 | if (demoOption == "input") { 111 | var inputKind = cmdParts.getOrNull(2) 112 | var inputModifier = cmdParts.getOrNull(3) 113 | when (inputKind) { 114 | "ranged" -> { 115 | if (inputModifier != null && inputModifier != "protected") { 116 | outputSystem( 117 | "\n\nInvalid option for DEMO INPUT RANGED, only PROTECTED or no argument is valid." 118 | ) 119 | } else { 120 | val protected = inputModifier == "protected" 121 | val inputCode = 122 | "%i20" + 123 | if (protected) { 124 | "+" 125 | } else { 126 | "" 127 | } + 128 | ";" 129 | val inputLabel = 130 | "Enter " + 131 | if (protected) { 132 | "Protected" 133 | } else { 134 | " Ranged " 135 | } + 136 | " Input:" 137 | output( 138 | "\n\n&c- +--------------------+\n&l-$inputLabel&c- |$inputCode|\n&c- +--------------------+&00" 139 | ) 140 | activelyDemoingInput = true 141 | } 142 | } 143 | "infinite" -> { 144 | if (inputModifier != null && inputModifier != "protected") { 145 | outputSystem( 146 | "\n\nInvalid option for DEMO INPUT INFINITE, only PROTECTED or no argument is valid." 147 | ) 148 | } else { 149 | val protected = inputModifier == "protected" 150 | if (protected) { 151 | output("\n\n&l-::> %i+;") 152 | } else { 153 | output("\n\n&l-::> ") 154 | } 155 | activelyDemoingInput = true 156 | } 157 | } 158 | else -> 159 | outputSystem( 160 | "\n\nValid arguments to INPUT are RANGED [PROTECTED] or INFINITE [PROTECTED]." 161 | ) 162 | } 163 | } else { 164 | outputSystem("\n\nThe valid argument to DEMO is INPUT.") 165 | } 166 | } 167 | cmdParts.first() == "exit" -> exitProcess(0) 168 | cmdParts.first() == "help" -> output(HELP_STRING) 169 | else -> 170 | outputSystem( 171 | "\n\nYou must enter a command! Valid commands are INFO, LICENSE, DEMO, ANSI, and EXIT" 172 | ) 173 | } 174 | 175 | if (!activelyDemoingInput) { 176 | output("\n\n&ob>>&00 ") 177 | } 178 | } 179 | 180 | public override fun output(message: String) { 181 | if (console?.useANSIColorCodes ?: false) { 182 | super.output(convertToANSIColors(message)) 183 | } else { 184 | super.output(message) 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/demo/DragonConsoleFrame.kt: -------------------------------------------------------------------------------- 1 | package dev.bbuck.dragonconsole.demo 2 | 3 | import dev.bbuck.dragonconsole.DragonConsole 4 | import java.awt.Toolkit 5 | import javax.swing.JFrame 6 | 7 | /** 8 | * A simple entrypoint for a GUI with a DragonConsole already added. Constructing a new frame 9 | * without a title uses a default title and without a console creates a new console instance. 10 | * 11 | * @param title is the title of the frame. 12 | * @param console is the console instance to use in the frame if one has already been defined. 13 | */ 14 | class DragonConsoleFrame 15 | @JvmOverloads 16 | constructor( 17 | title: String = "DragonConsoleFrame ${DragonConsole.getVersion()}", 18 | val console: DragonConsole = DragonConsole() 19 | ) : JFrame(title) { 20 | init { 21 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) 22 | setResizable(false) 23 | add(console) 24 | pack() 25 | console.setInputFocus() 26 | centerWindow() 27 | } 28 | 29 | // support the console only which won't be generated via JvmOverloads 30 | constructor(dragonConsole: DragonConsole) : this(console = dragonConsole) 31 | 32 | // centers the window in the current screen 33 | private fun centerWindow() { 34 | val defaultToolkit = Toolkit.getDefaultToolkit() 35 | val screenSize = defaultToolkit.screenSize 36 | setLocation((screenSize.width / 2) - (width / 2), (screenSize.height / 2) - (height / 2)) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/file/BUILD: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") 2 | 3 | package(default_visibility = ["//src/main:__subpackages__"]) 4 | 5 | kt_jvm_library( 6 | name = "file_processor", 7 | srcs = ["FileProcessor.kt"], 8 | resources = [ 9 | "//src/main/resources/com/eleet/dragonconsole:font/dvsm.ttf", 10 | ], 11 | ) 12 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/file/FileProcessor.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("FileProcessor") 2 | 3 | package dev.bbuck.dragonconsole.file 4 | 5 | import java.awt.Font 6 | import java.io.BufferedReader 7 | import java.io.File 8 | import java.io.FileReader 9 | import java.io.IOException 10 | import java.io.InputStreamReader 11 | import javax.swing.JOptionPane 12 | import javax.swing.JOptionPane.showMessageDialog 13 | 14 | /** 15 | * Reads the contents of the file pointed to by the give file path. 16 | * 17 | * @param filePath is the absolute or relative path to the file. 18 | * @return the entire contents of the file as a string. 19 | * @throws IllegalArgumentException if the file does not exist 20 | * 21 | * @since 3.0 22 | * @author Brandon Buck 23 | */ 24 | fun readText(filePath: String): String = readText(File(filePath)) 25 | 26 | /** 27 | * Reads the contents of the given file. 28 | * 29 | * @param file is the file that will have it's content read. 30 | * @return the entire contents of the file as a string. 31 | * @throws IllegalArgumentException if the file does not exist 32 | * 33 | * @since 3.0 34 | * @author Brandon Buck 35 | */ 36 | fun readText(file: File): String { 37 | if (!file.exists()) { 38 | throw IllegalArgumentException("File does not exist at path \"${file.absolutePath}\"") 39 | } 40 | 41 | val contents = StringBuilder() 42 | 43 | val fileReader: FileReader? 44 | val lineReader: BufferedReader? 45 | 46 | try { 47 | fileReader = FileReader(file) 48 | lineReader = BufferedReader(fileReader) 49 | 50 | var line = lineReader.readLine() 51 | while (line != null) { 52 | contents.append(line).append('\n') 53 | line = lineReader.readLine() 54 | } 55 | 56 | lineReader.close() 57 | fileReader.close() 58 | } catch (e: IOException) { 59 | showMessageDialog( 60 | null, 61 | "Error #0008\nFailed to read the given file.\n${e.message}", 62 | "Exception Reading File", 63 | JOptionPane.ERROR_MESSAGE 64 | ) 65 | } 66 | 67 | return contents.toString() 68 | } 69 | 70 | /** 71 | * Reads a file that is stored in the JAR alongside DragonConsole. 72 | * 73 | * @param file is the name of the resource that should be read. 74 | * @return the entire contents of the file as a string. 75 | * 76 | * @since 3.0 77 | * @author Brandon Buck 78 | */ 79 | fun readDCResource(file: String): String { 80 | val contents = StringBuilder() 81 | 82 | try { 83 | val inStream = 84 | object {}.javaClass.getResourceAsStream("/com/eleet/dragonconsole/resources/$file") 85 | val inStreamReader = InputStreamReader(inStream) 86 | val lineReader = BufferedReader(inStreamReader) 87 | 88 | var line = lineReader.readLine() 89 | while (line != null) { 90 | contents.append(line).append('\n') 91 | line = lineReader.readLine() 92 | } 93 | 94 | lineReader.close() 95 | inStreamReader.close() 96 | inStream.close() 97 | } catch (e: IOException) { 98 | showMessageDialog( 99 | null, 100 | "Error #0009\nFailed to read the file from the jar!\n${e.message}", 101 | "Exception Reading Resource", 102 | JOptionPane.ERROR_MESSAGE 103 | ) 104 | } 105 | 106 | return contents.toString() 107 | } 108 | 109 | /** 110 | * Reads the font file stored alongside the DragonConsole in the JAR file. 111 | * 112 | * @return the font read from the JAR. 113 | * 114 | * @since 3.0 115 | * @author Brandon Buck 116 | */ 117 | fun getConsoleFont(): Font? { 118 | var font: Font? = null 119 | 120 | try { 121 | val inStream = 122 | object {}.javaClass.getResourceAsStream("/com/eleet/dragonconsole/font/dvsm.ttf") 123 | font = Font.createFont(Font.PLAIN, inStream) 124 | inStream.close() 125 | } catch (e: IOException) { 126 | showMessageDialog( 127 | null, 128 | "Error #0010\nFailed to load the font file from the jar!\n${e.message}", 129 | "Exception Reading Font", 130 | JOptionPane.ERROR_MESSAGE 131 | ) 132 | } 133 | 134 | return font 135 | } 136 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/log/BUILD: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") 2 | 3 | package(default_visibility = ["//src/main:__subpackages__"]) 4 | 5 | kt_jvm_library( 6 | name = "debug", 7 | srcs = ["Debug.kt"], 8 | ) 9 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/log/Debug.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("Debug") 2 | 3 | package dev.bbuck.dragonconsole.log 4 | 5 | private var debugOn = false 6 | 7 | /** 8 | * Turn on the debug mode so that debug logs will print. 9 | * 10 | * @since 3.0 11 | * @author Brandon Buck 12 | */ 13 | fun turnOn() { 14 | debugOn = true 15 | } 16 | 17 | /** 18 | * Turn off the debug mode so that debug logs no longer print. 19 | * 20 | * @since 3.0 21 | * @author Brandon Buck 22 | */ 23 | fun turnOff() { 24 | debugOn = false 25 | } 26 | 27 | /** 28 | * Print a debug message if the debug mode is enabled. 29 | * 30 | * @param msg is what should be printed if debug is enabled. 31 | * 32 | * @since 3.0 33 | * @author Brandon Buck 34 | */ 35 | fun print(msg: String) { 36 | if (debugOn) { 37 | println(msg) 38 | } 39 | } 40 | 41 | /** 42 | * Friendlier Kotlin name for `print`. 43 | * 44 | * @since 3.1 45 | * @author Brandon Buck 46 | */ 47 | fun debugLog(msg: String) { 48 | print(msg) 49 | } 50 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/text/Ansi.kt: -------------------------------------------------------------------------------- 1 | package dev.bbuck.dragonconsole.text 2 | 3 | import java.awt.Color 4 | import javax.swing.text.SimpleAttributeSet 5 | import javax.swing.text.Style 6 | import javax.swing.text.StyleConstants 7 | 8 | /** Provides utilities for converting to and from ANSI color codes and DragonConsole color codes. */ 9 | object ANSI { 10 | /** ANSI escape code that begins ANSI control codes. */ 11 | const val ESCAPE = '\u001b' 12 | 13 | // Bright ANSI standard colors 14 | @JvmField public val INTENSE_BLACK = Color.GRAY.darker() 15 | @JvmField public val INTENSE_RED = Color.RED 16 | @JvmField public val INTENSE_GREEN = Color.GREEN 17 | @JvmField public val INTENSE_YELLOW = Color.YELLOW 18 | @JvmField public val INTENSE_BLUE = Color(66, 66, 255) 19 | @JvmField public val INTENSE_MAGENTA = Color.MAGENTA 20 | @JvmField public val INTENSE_CYAN = Color.CYAN 21 | @JvmField public val INTENSE_WHITE = Color.WHITE 22 | 23 | // Colors associated to ANSI standard colors 24 | @JvmField public val BLACK = Color.BLACK 25 | @JvmField public val RED = INTENSE_RED.darker() 26 | @JvmField public val GREEN = INTENSE_GREEN.darker() 27 | @JvmField public val YELLOW = INTENSE_YELLOW.darker() 28 | @JvmField public val BLUE = INTENSE_BLUE.darker() 29 | @JvmField public val MAGENTA = INTENSE_MAGENTA.darker() 30 | @JvmField public val CYAN = INTENSE_CYAN.darker() 31 | @JvmField public val WHITE = Color.GRAY.brighter() 32 | 33 | /** Normal colors in ANSI color order (0 -> Black, 1 -> Red, etc...) */ 34 | @JvmField 35 | public val NORMAL_COLORS = listOf(BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE) 36 | 37 | /** Intense colors in ANSI color order (0 -> Black, 1 -> Red, etc...) */ 38 | @JvmField 39 | public val INTENSE_COLORS = 40 | listOf( 41 | INTENSE_BLACK, 42 | INTENSE_RED, 43 | INTENSE_GREEN, 44 | INTENSE_YELLOW, 45 | INTENSE_BLUE, 46 | INTENSE_MAGENTA, 47 | INTENSE_CYAN, 48 | INTENSE_WHITE 49 | ) 50 | 51 | /** Signifies that following colors should be "bright" or "intense" */ 52 | const val BRIGHT_CODE = 1 53 | 54 | /** Resets the current ANSI color settings back to the default. */ 55 | const val RESET = 0 56 | 57 | /** Special color that represents the "default" color. */ 58 | const val DEFAULT_COLOR_CODE = 9 59 | 60 | /** Color codes are always in 0 to 7. */ 61 | val VALID_COLOR_RANGE = 0..7 62 | 63 | /** Foreground codes are 30-37, but we only care about the digit. */ 64 | const val FOREGROUND_DIGIT = 3 65 | 66 | /** Background codes are 40-47, but we only care about the digit. */ 67 | const val BACKGROUND_DIGIT = 4 68 | 69 | /** Numeric regular expression for filtering out ANSI codes not needed. */ 70 | val NUMERIC_CODE = """\A\d+\z""".toRegex() 71 | 72 | /** 73 | * ANSI code to use the default foreground and background, used as a default for empty/incorrect 74 | * DCCode provided for conversion. 75 | */ 76 | const val USE_DEFAULTS_CODE = "$ESCAPE[39;49m" 77 | 78 | /** 79 | * Convert the string ANSI code into a `SimpleAttributeSet` for use in a `StyledDocument`. This 80 | * method only considers the ANSI color code portions and ignores the rest of the code. This 81 | * method does not validate the code. 82 | * 83 | * @param existingAttributeSet is the current active document style as ANSI codes modify 84 | * existing styles instead of replacing everything about them. 85 | * @param ansiCode is the actual string representation of current ANSI code. 86 | * @param defaultStyle is the base style of the document we pull from when the ANSI code refers 87 | * to reverting to the default values. 88 | * @return the modified `SimpleAttributeSet` with the new current ANSI color configuration. 89 | * 90 | * @since 3.0 91 | * @author Brandon Buck 92 | */ 93 | @JvmStatic 94 | public fun getANSIAttribute( 95 | existingAttributeSet: SimpleAttributeSet?, 96 | ansiCode: String, 97 | defaultStyle: Style 98 | ): SimpleAttributeSet? { 99 | if (ansiCode.length <= 3) { 100 | return null 101 | } 102 | 103 | var ansiAttributeSet = existingAttributeSet 104 | 105 | if (ansiAttributeSet == null) { 106 | ansiAttributeSet = SimpleAttributeSet() 107 | } 108 | 109 | var codeParts = listOf() 110 | // minimum code length would be the escape, brace, and 'm' (end of code) 111 | if (ansiCode.length > 3) { 112 | // trims the escape and opne character as well as the final 'm' ending 113 | // the code 114 | codeParts = 115 | ansiCode.substring(2, ansiCode.length - 1) 116 | .split(';') 117 | .filter { it.matches(NUMERIC_CODE) } 118 | .map(String::toInt) 119 | } 120 | 121 | var brightColors = false 122 | for (codePart in codeParts) { 123 | if (codePart == 0) { 124 | brightColors = false 125 | ansiAttributeSet = SimpleAttributeSet() 126 | } else if (codePart == 1) { 127 | brightColors = true 128 | } 129 | 130 | val tensDigit = codePart / 10 131 | val onesDigit = codePart % 10 132 | 133 | if (onesDigit in VALID_COLOR_RANGE) { 134 | val color = getColorFromAnsiCode(codePart, brightColors) 135 | when (tensDigit) { 136 | FOREGROUND_DIGIT -> StyleConstants.setForeground(ansiAttributeSet, color) 137 | BACKGROUND_DIGIT -> StyleConstants.setBackground(ansiAttributeSet, color) 138 | } 139 | } else if (onesDigit == DEFAULT_COLOR_CODE) { 140 | if (tensDigit == FOREGROUND_DIGIT) { 141 | val color = StyleConstants.getForeground(defaultStyle) 142 | StyleConstants.setBackground(ansiAttributeSet, color) 143 | } else if (tensDigit == BACKGROUND_DIGIT) { 144 | val color = StyleConstants.getBackground(defaultStyle) 145 | StyleConstants.setBackground(ansiAttributeSet, color) 146 | } 147 | } 148 | } 149 | 150 | return ansiAttributeSet 151 | } 152 | 153 | /** 154 | * Converts a given DCCode into an ANSI color code based on the color values of the current 155 | * theme. If no match is found or an invalid code is provided then a default "use default color" 156 | * (`[39;49m`) is returned. 157 | * 158 | * @param dcCode is the code that should be converted to an ANSI code. 159 | * @param colors is the list of colors currently present in the DragonConsole theme. 160 | * @return the best guess at an ANSI color code equivalent to the provided DCCode. 161 | * 162 | * @since 3.0 163 | * @author Brandon Buck 164 | */ 165 | @JvmStatic 166 | public fun getANSICodeFromDCCode(dcCode: String, colors: List): String { 167 | if (dcCode.length != 3) { 168 | return USE_DEFAULTS_CODE 169 | } 170 | 171 | val colorMap = colors.associate { it.charCode to it } 172 | 173 | // DCCode format is &fb and we only care about the foreground and background 174 | // characters 175 | val foreground = dcCode[1] 176 | val background = dcCode[2] 177 | 178 | val ansiCode = mutableListOf("0") 179 | 180 | if (colorMap.containsKey(foreground)) { 181 | val textColor = colorMap.getValue(foreground) 182 | var bright = false 183 | var colorIndex = NORMAL_COLORS.indexOf(textColor.color) 184 | if (colorIndex < 0) { 185 | bright = true 186 | colorIndex = INTENSE_COLORS.indexOf(textColor.color) 187 | } 188 | 189 | if (colorIndex >= 0) { 190 | if (bright) { 191 | ansiCode.add("1") 192 | } 193 | ansiCode.add("$FOREGROUND_DIGIT$colorIndex") 194 | } 195 | } 196 | 197 | if (colorMap.containsKey(background)) { 198 | val textColor = colorMap.getValue(background) 199 | var bright = false 200 | var colorIndex = NORMAL_COLORS.indexOf(textColor.color) 201 | if (colorIndex < 0) { 202 | bright = true 203 | colorIndex = INTENSE_COLORS.indexOf(textColor.color) 204 | } 205 | 206 | if (colorIndex >= 0) { 207 | if (bright) { 208 | ansiCode.add("1") 209 | } 210 | ansiCode.add("$BACKGROUND_DIGIT$colorIndex") 211 | } 212 | } 213 | 214 | val generatedCode = 215 | ansiCode.joinToString(separator = ";", prefix = "$ESCAPE[", postfix = "m") 216 | if (generatedCode == "[0m") { 217 | return USE_DEFAULTS_CODE 218 | } else { 219 | return generatedCode 220 | } 221 | } 222 | 223 | /** 224 | * Convert all the DCCode characters in a block of text into corresponding ANSI color codes and 225 | * return the new string with ANSI color codes in it. 226 | * 227 | * @param text is the text contianing DCCodes. 228 | * @param colors are all the colors currently defined in the DragonConsole. 229 | * @param colorCodeChar is the character that denotes a DCCode follows, typically this will be 230 | * `&`. 231 | * @return the block of text provided withall DCCode's converted into rough equivalents of ANSI 232 | * codes. 233 | * 234 | * @since 3.0 235 | * @author Brandon Buck 236 | */ 237 | @JvmStatic 238 | public fun convertDCtoANSIColors( 239 | text: String, 240 | colors: List, 241 | colorCodeChar: Char 242 | ): String { 243 | val output = StringBuilder() 244 | 245 | var i = 0 246 | while (i < text.length) { 247 | if (text[i] == colorCodeChar) { 248 | if (i < text.length - 1 && text[i + 1] == colorCodeChar) { 249 | // double color code characters print a single color code 250 | // character 251 | output.append(colorCodeChar).append(colorCodeChar) 252 | i += 2 253 | continue 254 | } 255 | 256 | if (i < text.length - 2) { 257 | val code = text.substring(i, i + 3) 258 | 259 | val ansiCode = getANSICodeFromDCCode(code, colors) 260 | output.append(ansiCode) 261 | i += 3 262 | continue 263 | } 264 | } 265 | 266 | output.append(text[i]) 267 | ++i 268 | } 269 | 270 | return output.toString() 271 | } 272 | 273 | /** 274 | * Convert the ANSI color codes in the given text to DragonConsole color codes. 275 | * 276 | * @param text contains the ANSI color codes that need to be converted. 277 | * @param colors are the set of colors currently added to the DragonConsole. 278 | * @param colorCodeChar is the character that begins a DragonConsole color code. 279 | * @param defaultStyle is the default foreground and background color. 280 | * @return the text with all ANSI color codes converted into DragonConsole color codes. 281 | * 282 | * @since 3.0 283 | * @author Brandon Buck 284 | */ 285 | @JvmStatic 286 | public fun convertANSIToDCColors( 287 | text: String, 288 | colors: List, 289 | colorCodeChar: Char, 290 | defaultStyle: String 291 | ): String { 292 | val output = StringBuilder() 293 | 294 | var i = 0 295 | while (i < text.length) { 296 | if (text[i] == ESCAPE) { 297 | val endIndex = text.indexOf('m', i + 1) 298 | if (endIndex >= 0) { 299 | val ansiCode = text.substring(i, endIndex + 1) 300 | val dcCode = 301 | getDCCodeFromAnsiCode(ansiCode, colors, colorCodeChar, defaultStyle) 302 | output.append(dcCode) 303 | i = endIndex + 1 304 | continue 305 | } 306 | } 307 | 308 | output.append(text[i]) 309 | ++i 310 | } 311 | 312 | return output.toString() 313 | } 314 | 315 | /** 316 | * Converts a given ANSI code into it's DCCode equivalent based on the current defined colors in 317 | * the console. 318 | * 319 | * @param code is the ANSI code that needs to be converted. 320 | * @param colors are all the colors defined in the Console. 321 | * @param colorCodeChar is the character that denotes the beginning fo a DCCode, which is 322 | * typically `&`. 323 | * @param defaultStyle is the "default" DCCode to pull color characters from as needed. 324 | * @return the DCCode equivalent (based on color value) of the input ANSI code. 325 | * 326 | * @since 3.0 327 | * @author Brandon Buck 328 | */ 329 | private fun getDCCodeFromAnsiCode( 330 | ansiCode: String, 331 | colors: List, 332 | colorCodeChar: Char, 333 | defaultStyle: String 334 | ): String { 335 | var bright = false 336 | val ansiCodeContents = ansiCode.substring(2) 337 | var foreground = defaultStyle[0] 338 | var background = defaultStyle[1] 339 | 340 | val ansiParts = ansiCodeContents.split(";") 341 | for (part in ansiParts) { 342 | if (part.matches("""\d+""".toRegex())) { 343 | var colorCode = part.toInt() 344 | when (colorCode) { 345 | 0 -> { 346 | bright = false 347 | } 348 | 1 -> { 349 | bright = true 350 | } 351 | in 30..37 -> { 352 | foreground = 353 | getDCCharCodeFromColor( 354 | getColorFromAnsiCode(colorCode, bright), 355 | colors 356 | ) 357 | } 358 | 39 -> { 359 | foreground = defaultStyle[0] 360 | } 361 | in 40..47 -> { 362 | background = 363 | getDCCharCodeFromColor( 364 | getColorFromAnsiCode(colorCode, bright), 365 | colors 366 | ) 367 | } 368 | 49 -> { 369 | background = defaultStyle[1] 370 | } 371 | } 372 | } 373 | } 374 | 375 | return "$colorCodeChar$foreground$background" 376 | } 377 | 378 | /** 379 | * Find the corresponding char code associated with a given color value based on what colors are 380 | * defined in the console. 381 | * 382 | * @param color is the search color, the color for which a character is desired. 383 | * @param colors are all the colors currently defined in the console. 384 | * @return the character representing the input color or simply an empty character. 385 | * 386 | * @since 3.0 387 | * @author Brandon Buck 388 | */ 389 | private fun getDCCharCodeFromColor(color: Color, colors: List): Char { 390 | for (textColor in colors) { 391 | if (textColor.color == color) { 392 | return textColor.charCode 393 | } 394 | } 395 | 396 | return ' ' 397 | } 398 | 399 | /** 400 | * Fetch the actual color specified by the given ANSI code. 401 | * 402 | * Valid colors fall in the range of 0 to 7 (with a 3 or 4 in the tens digit). Each of these 403 | * values directly corresponds to a color in ANSI so we fetch and return the correct color for 404 | * the code. 405 | * 406 | * @param code is the numeric ANSI code representing the color. 407 | * @param bright determines if the normal or intense color list should be used. 408 | * @return the associated color. 409 | * 410 | * @since 3.0 411 | * @author Brandon Buck 412 | */ 413 | private fun getColorFromAnsiCode(code: Int, bright: Boolean): Color { 414 | val colorCode = code % 10 415 | 416 | if (colorCode !in VALID_COLOR_RANGE) { 417 | throw IllegalArgumentException("Invalid ANSI color code '$code' provided") 418 | } 419 | 420 | if (bright) { 421 | return INTENSE_COLORS[colorCode] 422 | } 423 | 424 | return NORMAL_COLORS[colorCode] 425 | } 426 | } 427 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/text/BUILD: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") 2 | 3 | package(default_visibility = ["//src/main:__subpackages__"]) 4 | 5 | kt_jvm_library( 6 | name = "text_color", 7 | srcs = ["TextColor.kt"], 8 | ) 9 | 10 | kt_jvm_library( 11 | name = "document_styler", 12 | srcs = ["DocumentStyler.kt"], 13 | deps = [":text_color"], 14 | ) 15 | 16 | kt_jvm_library( 17 | name = "ansi", 18 | srcs = ["Ansi.kt"], 19 | deps = [":text_color"], 20 | ) 21 | 22 | kt_jvm_library( 23 | name = "input_string", 24 | srcs = ["InputString.kt"], 25 | deps = [ 26 | "//src/main/kotlin/dev/bbuck/dragonconsole/log:debug", 27 | ], 28 | ) 29 | 30 | kt_jvm_library( 31 | name = "stored_input", 32 | srcs = ["StoredInput.kt"], 33 | deps = [":input_string"], 34 | ) 35 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/text/DocumentStyler.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("DocumentStyler") 2 | 3 | package dev.bbuck.dragonconsole.text 4 | 5 | import java.awt.Font 6 | import javax.swing.text.SimpleAttributeSet 7 | import javax.swing.text.StyleConstants 8 | import javax.swing.text.StyleContext 9 | import javax.swing.text.StyledDocument 10 | 11 | /** 12 | * Creates a style and adds it to the `StyledDocument`. 13 | * 14 | * Using the foreground and backgroun character codes it builds a new style name combining them and 15 | * adds this style to the document updating the actual foreground and background color of the style. 16 | * 17 | * @param document is the document that the newly created style should be added to. 18 | * @param foreground is the color representing the foreground color of the text in this style (color 19 | * of the text). 20 | * @param background is the color representing the background color of the text in this style (color 21 | * behind/around the text). 22 | * @return the updated document. 23 | * 24 | * @since 3.0 25 | * @author Brandon Buck 26 | */ 27 | private fun addNewStyle( 28 | document: StyledDocument, 29 | foreground: TextColor, 30 | background: TextColor 31 | ): StyledDocument { 32 | val styleName = "${foreground.charCode}${background.charCode}" 33 | val parentStyle = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE) 34 | 35 | val temp = document.addStyle(styleName, parentStyle) 36 | StyleConstants.setForeground(temp, foreground.color) 37 | StyleConstants.setBackground(temp, background.color) 38 | 39 | return document 40 | } 41 | 42 | /** 43 | * Update a `SimpleAttributeSet's` font with the provided font. 44 | * 45 | * @param attributeSet is the attribute set that will have it's font updated. 46 | * @param font is the font that should be applied to the provided `SimpleAttributeSet`. 47 | * @return the `SimpleAttributeSet` after having had it's font updated. 48 | * 49 | * @since 3.0 50 | * @author Brandon Buck 51 | */ 52 | private fun setSasFont(attributeSet: SimpleAttributeSet, font: Font): SimpleAttributeSet { 53 | StyleConstants.setFontFamily(attributeSet, font.family) 54 | StyleConstants.setFontSize(attributeSet, font.size) 55 | StyleConstants.setBold(attributeSet, font.isBold) 56 | StyleConstants.setItalic(attributeSet, font.isItalic) 57 | 58 | return attributeSet 59 | } 60 | 61 | /** 62 | * Change the font for the entire document. 63 | * 64 | * @param document is the document that should have it's font updated. 65 | * @param font is the new font for the document's text. 66 | * @return the `StyledDocument` after the font has been changed. 67 | * 68 | * @since 3.0 69 | * @author Brandon Buck 70 | */ 71 | fun changeFont(document: StyledDocument, font: Font): StyledDocument { 72 | var newAttributeSet = SimpleAttributeSet() 73 | newAttributeSet = setSasFont(newAttributeSet, font) 74 | document.setCharacterAttributes(0, document.length, newAttributeSet, false) 75 | 76 | return document 77 | } 78 | 79 | /** 80 | * Add a new `TextColor` to the provided `StyledDocument`. 81 | * 82 | * Adding a color requires all the previously added colors so that the new color can be setup with 83 | * all existing colors as background colors as well as all previously defined colors as foreground 84 | * colors with the new color acting as foreground and background (respectively). 85 | * 86 | * @param document the dcoument that the new color will be added to. 87 | * @param newColor is the new text color that will be added to the document. 88 | * @apram allColors is the list of all the existing colors that have been added previously. 89 | * @return the updated document containing the necessary rules for the new color. 90 | * 91 | * @since 3.0 92 | * @author Brandon Buck 93 | */ 94 | fun addNewColor( 95 | document: StyledDocument, 96 | newColor: TextColor, 97 | allColors: List 98 | ): StyledDocument { 99 | var updatedDocument = document 100 | for (color in allColors) { 101 | // apply all color backgrounds to the new color as foreground 102 | updatedDocument = addNewStyle(updatedDocument, newColor, color) 103 | // apply all color foregrounds to the new color as background 104 | updatedDocument = addNewStyle(updatedDocument, color, newColor) 105 | } 106 | 107 | return updatedDocument 108 | } 109 | 110 | /** 111 | * Remove a color from the document. 112 | * 113 | * This has to remove the occurrences of the color as a foreground and as a background which 114 | * requires all the colors currently in the document. 115 | * 116 | * @param document is the document the color will be removed from. 117 | * @param colorToRemove is the color that will be removed from the provided document. 118 | * @param allColors is all the current colors added to the document. 119 | * @return the updated `StyledDocument`. 120 | * 121 | * @since 3.0 122 | * @author BrandonBuck 123 | */ 124 | fun removeColor( 125 | document: StyledDocument, 126 | colorToRemove: TextColor, 127 | allColors: List 128 | ): StyledDocument { 129 | var updatedDocument = document 130 | 131 | updatedDocument.removeStyle("${colorToRemove.charCode}${colorToRemove.charCode}") 132 | 133 | for (color in allColors) { 134 | val colorAsForeground = "${colorToRemove.charCode}${color.charCode}" 135 | val colorAsBackground = "${color.charCode}${colorToRemove.charCode}" 136 | 137 | updatedDocument.removeStyle(colorAsForeground) 138 | updatedDocument.removeStyle(colorAsBackground) 139 | } 140 | 141 | return updatedDocument 142 | } 143 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/text/InputString.kt: -------------------------------------------------------------------------------- 1 | package dev.bbuck.dragonconsole.text 2 | 3 | import dev.bbuck.dragonconsole.log.debugLog 4 | 5 | // Leaving undocumented, this looks like a poor implementation of StringBuilder 6 | // and is obselete as of the Kotlin clean up 7 | @Deprecated("Poor man's StringBuilder", ReplaceWith("StringBuilder")) 8 | public class InputString(initial: String) { 9 | val builder: StringBuilder = StringBuilder() 10 | 11 | init { 12 | builder.append(initial) 13 | } 14 | 15 | public fun clear() { 16 | builder.clear() 17 | } 18 | 19 | public fun append(other: String) { 20 | builder.append(other) 21 | debugLog("\"$builder\" - append(\"$other\")") 22 | } 23 | 24 | public fun insert(where: Int, toInsert: String) { 25 | builder.insert(where, toInsert) 26 | 27 | debugLog("\"$builder\" - insert($where, \"$toInsert\")") 28 | } 29 | 30 | public fun remove(start: Int, length: Int) { 31 | val end = start + length 32 | 33 | builder.delete(start, end) 34 | 35 | debugLog("\"$builder\" - remove($start, $length)") 36 | } 37 | 38 | public fun rangeRemove(start: Int, length: Int) { 39 | remove(start, length) 40 | builder.append(' ') 41 | 42 | debugLog("\"$builder\" - rangeRemove($start, $length)") 43 | } 44 | 45 | public fun rangeInsert(where: Int, value: String): Boolean { 46 | if (where >= builder.length || !endIsEmpty()) { 47 | return false 48 | } 49 | 50 | builder.replace(where, where + 1, value) 51 | 52 | debugLog("\"$builder\" - rangeInsert($where, \"$value\")") 53 | 54 | return true 55 | } 56 | 57 | public fun replace(start: Int, length: Int, value: String) { 58 | if (start >= builder.length || start + length >= builder.length) { 59 | append(value) 60 | 61 | return 62 | } 63 | 64 | val end = start + length 65 | 66 | builder.replace(start, end, value) 67 | 68 | debugLog("\"$builder\" - replace($start, $length, \"$value\")") 69 | } 70 | 71 | public fun set(newValue: String) { 72 | builder.clear().append(newValue) 73 | } 74 | 75 | public fun get(): String = builder.toString() 76 | 77 | public fun endIsEmpty(): Boolean = builder.last() == ' ' 78 | 79 | public fun length(): Int = builder.length 80 | 81 | public override fun toString(): String = builder.toString() 82 | } 83 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/text/StoredInput.kt: -------------------------------------------------------------------------------- 1 | package dev.bbuck.dragonconsole.text 2 | 3 | class StoredInput( 4 | var isInfinite: Boolean, 5 | var protected: Boolean, 6 | var range: Int, 7 | val input: InputString 8 | ) { 9 | fun matches(isInfinite: Boolean, protected: Boolean, range: Int): Boolean { 10 | if (this.isInfinite != isInfinite) { 11 | return false 12 | } 13 | 14 | if (this.isInfinite) { 15 | return this.protected == protected 16 | } 17 | 18 | if (this.range == range && this.protected == protected) { 19 | return true 20 | } 21 | 22 | return false 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/text/TextColor.kt: -------------------------------------------------------------------------------- 1 | package dev.bbuck.dragonconsole.text 2 | 3 | import java.awt.Color 4 | 5 | private val ILLEGAL_TEXT_COLOR_VARIABLES = setOf('0', '-') 6 | 7 | /** 8 | * A TextColor contains a character and a color. 9 | * 10 | * This represents a DCCC color code to perform colorization of text in the DragonConsole. 11 | * 12 | * @since 3.0 13 | * @author Brandon Buck 14 | */ 15 | public data class TextColor 16 | @JvmOverloads 17 | constructor(val charCode: Char = '\u0000', val color: Color = Color.WHITE) : Comparable { 18 | init { 19 | if (charCode in ILLEGAL_TEXT_COLOR_VARIABLES) { 20 | throw IllegalArgumentException("Cannot use reserved character '$charCode' in TextColor") 21 | } 22 | } 23 | 24 | /** 25 | * Compare this TextColor's char to the other TextColor's char. 26 | * 27 | * @param other is the TextColor to compare this TextColor to. 28 | * @return the ordering representing the relationship between this TextColor and the other 29 | * TextColor. 30 | * 31 | * @since 3.0 32 | * @author Brandon Buck 33 | */ 34 | override operator fun compareTo(other: TextColor): Int = charCode.compareTo(other.charCode) 35 | 36 | override fun toString(): String = "Code: $charCode = $color" 37 | } 38 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/ui/BUILD: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") 2 | 3 | package(default_visibility = ["//src/main:__subpackages__"]) 4 | 5 | kt_jvm_library( 6 | name = "prompt_label", 7 | srcs = ["PromptLabel.kt"], 8 | visibility = ["//visibility:private"], 9 | deps = [ 10 | "//src/main/kotlin/dev/bbuck/dragonconsole/text:text_color", 11 | ], 12 | ) 13 | 14 | kt_jvm_library( 15 | name = "prompt_panel", 16 | srcs = ["PromptPanel.kt"], 17 | deps = [ 18 | ":prompt_label", 19 | "//src/main/kotlin/dev/bbuck/dragonconsole/text:text_color", 20 | ], 21 | ) 22 | 23 | kt_jvm_library( 24 | name = "input_controller", 25 | srcs = ["InputController.kt"], 26 | deps = [ 27 | "//src/main/kotlin/dev/bbuck/dragonconsole/text:input_string", 28 | "//src/main/kotlin/dev/bbuck/dragonconsole/text:stored_input", 29 | ], 30 | ) 31 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/ui/InputController.kt: -------------------------------------------------------------------------------- 1 | package dev.bbuck.dragonconsole.ui 2 | 3 | import dev.bbuck.dragonconsole.text.InputString 4 | import dev.bbuck.dragonconsole.text.StoredInput 5 | import java.awt.Toolkit 6 | import javax.swing.JOptionPane 7 | import javax.swing.JOptionPane.showMessageDialog 8 | import javax.swing.JTextPane 9 | import javax.swing.text.AbstractDocument 10 | import javax.swing.text.AttributeSet 11 | import javax.swing.text.DocumentFilter 12 | 13 | const val BYPASS = "-" 14 | 15 | class InputController(var inputAttributeSet: AttributeSet?) : DocumentFilter() { 16 | private var inputRangeStart = 0 17 | var rangeEnd = 0 18 | var protected = false 19 | val inputString = InputString("") 20 | var isReceivingInput = false 21 | var consoleTextPane: JTextPane? = null 22 | var protectedChar = "*" 23 | var bypassRemove = false 24 | var ignoreInput = false 25 | var stored: StoredInput? = null 26 | var consoleInputMethod = true 27 | 28 | fun installConsole(textPane: JTextPane) { 29 | consoleTextPane = textPane 30 | } 31 | 32 | fun isProtected(): Boolean = protected 33 | 34 | fun getBypassPrefix(): String = BYPASS 35 | 36 | fun reset() { 37 | inputRangeStart = -1 38 | rangeEnd = 0 39 | protected = false 40 | inputString.clear() 41 | isReceivingInput = false 42 | } 43 | 44 | public fun setRangeStart(value: Int) { 45 | if (!isReceivingInput) { 46 | return 47 | } 48 | 49 | inputRangeStart = value 50 | 51 | if (rangeEnd > 0) { 52 | rangeEnd += value 53 | } 54 | } 55 | 56 | public fun getRangeStart() = inputRangeStart 57 | 58 | fun setInput(newInput: String) { 59 | if (!isReceivingInput || !isInfiniteInput()) { 60 | return 61 | } 62 | 63 | val styledDoc = consoleTextPane?.getStyledDocument() 64 | if (styledDoc == null) { 65 | return 66 | } 67 | 68 | val docLength = styledDoc.length 69 | bypassRemove = true 70 | styledDoc.remove(inputRangeStart, docLength - inputRangeStart) 71 | inputString.set(newInput) 72 | 73 | val prefix = 74 | if (consoleInputMethod) { 75 | BYPASS 76 | } else { 77 | "" 78 | } 79 | 80 | val newString = 81 | if (protected) { 82 | getProtectedString(newInput.length) 83 | } else { 84 | newInput 85 | } 86 | styledDoc.insertString(inputRangeStart, "$prefix$newString", inputAttributeSet) 87 | } 88 | 89 | fun getInputRangeEnd() = rangeEnd 90 | 91 | fun isInfiniteInput(): Boolean = rangeEnd == -1 92 | 93 | fun setInputStyle(inputCode: String): Boolean { 94 | inputRangeStart = -1 95 | rangeEnd = 0 96 | protected = false 97 | inputString.clear() 98 | isReceivingInput = true 99 | 100 | if (inputCode == "%i;") { 101 | rangeEnd = -1 102 | 103 | return false 104 | } 105 | 106 | var inputStyle = inputCode.substring(2, inputCode.length - 1) 107 | if (inputStyle.isEmpty()) { 108 | rangeEnd = -1 109 | 110 | return false 111 | } 112 | 113 | if (inputStyle.last() == '+' || inputStyle.last() == '-') { 114 | protected = inputStyle.last() == '+' 115 | inputStyle = inputStyle.substring(0, inputStyle.length - 1) 116 | } 117 | 118 | if (inputStyle.length == 0) { 119 | rangeEnd = -1 120 | 121 | return false 122 | } 123 | 124 | rangeEnd = inputStyle.toInt() 125 | inputString.set(getInputRangeString()) 126 | 127 | return true 128 | } 129 | 130 | fun getInputRangeString(): String { 131 | if (!isReceivingInput || rangeEnd <= 0) { 132 | return "" 133 | } 134 | 135 | val start = 136 | if (inputRangeStart > 0) { 137 | inputRangeStart 138 | } else { 139 | 0 140 | } 141 | val numSpaces = rangeEnd - start 142 | return " ".repeat(numSpaces) 143 | } 144 | 145 | fun getInputRangeStart(): Int = 146 | if (isReceivingInput) { 147 | inputRangeStart 148 | } else { 149 | -1 150 | } 151 | 152 | fun clearText() { 153 | reset() 154 | bypassRemove = true 155 | val styledDoc = consoleTextPane?.getStyledDocument() 156 | if (styledDoc == null) { 157 | return 158 | } 159 | styledDoc.remove(0, styledDoc.length) 160 | } 161 | 162 | fun setBasicInput(startPosition: Int) { 163 | inputRangeStart = startPosition 164 | rangeEnd = -1 165 | protected = false 166 | inputString.clear() 167 | isReceivingInput = true 168 | } 169 | 170 | fun setProtectedChar(protectedChar: Char) { 171 | this.protectedChar = protectedChar.toString() 172 | } 173 | 174 | fun getInput(): String { 175 | isReceivingInput = false 176 | 177 | return inputString.get().trim() 178 | } 179 | 180 | override fun insertString( 181 | filterBypass: FilterBypass, 182 | offset: Int, 183 | stringValue: String, 184 | attributeSet: AttributeSet 185 | ) { 186 | when { 187 | stringValue.startsWith(BYPASS) -> { 188 | val insertable = stringValue.substring(BYPASS.length) 189 | filterBypass.insertString(offset, insertable, attributeSet) 190 | } 191 | (isReceivingInput && isInfiniteInput() && offset >= inputRangeStart) -> { 192 | val insertable = 193 | if (protected) { 194 | getProtectedString(stringValue.length) 195 | } else { 196 | stringValue 197 | } 198 | filterBypass.insertString(offset, insertable, inputAttributeSet) 199 | inputString.insert(offset - inputRangeStart, insertable) 200 | } 201 | else -> Toolkit.getDefaultToolkit().beep() 202 | } 203 | } 204 | 205 | override fun replace( 206 | filterBypass: FilterBypass, 207 | offset: Int, 208 | length: Int, 209 | stringValue: String, 210 | attributeSet: AttributeSet 211 | ) { 212 | if (stringValue.startsWith(BYPASS)) { 213 | val withoutBypass = stringValue.substring(BYPASS.length) 214 | val replaceString = 215 | if (protected) { 216 | restoreProtectedString(withoutBypass) 217 | } else { 218 | withoutBypass 219 | } 220 | filterBypass.replace(offset, length, replaceString, attributeSet) 221 | 222 | return 223 | } 224 | 225 | if (ignoreInput) { 226 | return 227 | } 228 | 229 | if (!isReceivingInput || inputRangeStart <= 0 || offset < inputRangeStart) { 230 | Toolkit.getDefaultToolkit().beep() 231 | 232 | return 233 | } 234 | 235 | if (isInfiniteInput()) { 236 | if (protected) { 237 | filterBypass.replace(offset, length, protectedChar, inputAttributeSet) 238 | } else { 239 | filterBypass.replace(offset, length, stringValue, inputAttributeSet) 240 | } 241 | 242 | inputString.replace((offset - inputRangeStart), length, stringValue) 243 | 244 | return 245 | } 246 | 247 | if ((offset + 1) <= rangeEnd) { 248 | val inserted = inputString.rangeInsert((offset - inputRangeStart), stringValue) 249 | 250 | if (inserted) { 251 | val replaceString = 252 | if (protected) { 253 | protectedChar 254 | } else { 255 | stringValue 256 | } 257 | filterBypass.replace(offset, length, replaceString, inputAttributeSet) 258 | 259 | if (inputString.endIsEmpty()) { 260 | filterBypass.remove(rangeEnd - 1, 1) 261 | } else { 262 | filterBypass.remove(rangeEnd, 1) 263 | } 264 | 265 | return 266 | } 267 | } 268 | 269 | Toolkit.getDefaultToolkit().beep() 270 | } 271 | 272 | override fun remove(filterBypass: FilterBypass, offset: Int, length: Int) { 273 | if (ignoreInput) { 274 | return 275 | } 276 | 277 | if (bypassRemove) { 278 | bypassRemove = false 279 | filterBypass.remove(offset, length) 280 | 281 | return 282 | } 283 | 284 | if (!isReceivingInput || inputRangeStart <= 0 || offset < inputRangeStart) { 285 | Toolkit.getDefaultToolkit().beep() 286 | 287 | return 288 | } 289 | 290 | if (isInfiniteInput()) { 291 | filterBypass.remove(offset, length) 292 | val start = offset - inputRangeStart 293 | if (start < inputString.length()) { 294 | inputString.remove(start, length) 295 | } 296 | 297 | return 298 | } 299 | 300 | filterBypass.remove(offset, length) 301 | filterBypass.insertString((rangeEnd - 1), " ", inputAttributeSet) 302 | 303 | if (consoleTextPane?.caretPosition == rangeEnd) { 304 | consoleTextPane?.caretPosition = rangeEnd - 1 305 | } 306 | 307 | inputString.rangeRemove((offset - inputRangeStart), length) 308 | } 309 | 310 | public fun hasStoredInput(): Boolean = stored != null 311 | 312 | public fun storeInput() { 313 | stored = 314 | StoredInput( 315 | isInfiniteInput(), 316 | protected, 317 | (rangeEnd - inputRangeStart), 318 | InputString(inputString.get()) 319 | ) 320 | reset() 321 | } 322 | 323 | public fun restoreInput(): Boolean { 324 | val storedInput = stored 325 | 326 | if (storedInput == null || !isReceivingInput) { 327 | stored = null 328 | 329 | return false 330 | } 331 | 332 | if (!storedInput.matches(isInfiniteInput(), protected, (rangeEnd - inputRangeStart))) { 333 | stored = null 334 | 335 | return false 336 | } 337 | 338 | inputString.set(storedInput.input.get()) 339 | val end = 340 | if (isInfiniteInput()) { 341 | 0 342 | } else { 343 | rangeEnd - inputRangeStart 344 | } 345 | 346 | try { 347 | val replaceString = 348 | if (consoleInputMethod) { 349 | BYPASS + inputString.get() 350 | } else { 351 | inputString.get() 352 | } 353 | val document = consoleTextPane?.styledDocument as AbstractDocument 354 | document.replace(inputRangeStart, end, replaceString, inputAttributeSet) 355 | } catch (exc: Exception) { 356 | showMessageDialog( 357 | null, 358 | "Error #0013\nFailed to restore the Input!\n${exc.message}", 359 | "Error Caught", 360 | JOptionPane.ERROR_MESSAGE 361 | ) 362 | } 363 | 364 | stored = null 365 | 366 | return true 367 | } 368 | 369 | private fun getProtectedString(length: Int): String = protectedChar.repeat(length) 370 | 371 | private fun restoreProtectedString(original: String): String = 372 | protectedChar.repeat(original.length) 373 | } 374 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/ui/PromptLabel.kt: -------------------------------------------------------------------------------- 1 | package dev.bbuck.dragonconsole.ui 2 | 3 | import dev.bbuck.dragonconsole.text.TextColor 4 | import java.awt.Color 5 | import java.awt.Graphics 6 | import java.awt.Graphics2D 7 | import java.awt.RenderingHints 8 | import javax.swing.JLabel 9 | 10 | class PromptLabel(labelText: String, var defaultColor: String) : JLabel(labelText) { 11 | val textColors: MutableList = mutableListOf() 12 | var colorCodeChar = '&' 13 | 14 | fun addColor(textColor: TextColor) { 15 | textColors.add(textColor) 16 | repaint() 17 | } 18 | 19 | fun removeColor(textColor: TextColor) { 20 | textColors.remove(textColor) 21 | repaint() 22 | } 23 | 24 | fun clearColors() { 25 | textColors.clear() 26 | } 27 | 28 | override fun paintComponent(graphics: Graphics) { 29 | val labelText = super.getText() 30 | var startX = 0 31 | 32 | val processed = StringBuilder() 33 | var currentStyle = defaultColor 34 | var i = 0 35 | while (i < labelText.length) { 36 | val currentChar = labelText[i] 37 | if (currentChar == colorCodeChar) { 38 | if (i < text.length - 1 && labelText[i + 1] == colorCodeChar) { 39 | processed.append(colorCodeChar) 40 | // skipping the && (next character is skipped in loop 41 | // increment below 42 | i += 1 43 | } else if (i < text.length - 2) { 44 | startX = paintProcessed(processed.toString(), currentStyle, graphics, startX) 45 | processed.clear() 46 | currentStyle = mergeStyles(labelText.substring(i + 1, i + 3), currentStyle) 47 | 48 | // jump past the color code (two characters) 49 | i += 2 50 | } else { 51 | processed.append(labelText[i]) 52 | } 53 | } else { 54 | processed.append(labelText[i]) 55 | } 56 | 57 | ++i 58 | } 59 | 60 | paintProcessed(processed.toString(), currentStyle, graphics, startX) 61 | } 62 | 63 | // same as super.getText but trims color codes 64 | override fun getText(): String { 65 | return trimDCCC(super.getText()) 66 | } 67 | 68 | private fun paintProcessed(processed: String, style: String, graphics: Graphics, x: Int): Int { 69 | if (processed.isEmpty()) { 70 | return x 71 | } 72 | 73 | val graphics2d = graphics as Graphics2D 74 | graphics2d.setRenderingHint( 75 | RenderingHints.KEY_TEXT_ANTIALIASING, 76 | RenderingHints.VALUE_TEXT_ANTIALIAS_ON 77 | ) 78 | 79 | val bounds = graphics.getFontMetrics().getStringBounds(processed, graphics) 80 | val width = bounds.width.toInt() 81 | val height = bounds.height.toInt() 82 | val newX = x + width 83 | // What is 3?! 84 | val y = height - 3 85 | 86 | // draw background color 87 | graphics.setColor(getColorFromDCCC(style[1])) 88 | graphics.fillRect(x, 0, width, height) 89 | 90 | // draw text string 91 | graphics.setColor(getColorFromDCCC(style[0])) 92 | graphics.drawString(processed, x, y) 93 | 94 | return newX 95 | } 96 | 97 | private fun mergeStyles(newStyle: String, currentStyle: String): String { 98 | // if the newStyleis invalid, keep current style 99 | // a '--' newStyle means "use the same foreground and background" so just return current 100 | // style 101 | if (newStyle.length != 2 || newStyle == "--") { 102 | return currentStyle 103 | } 104 | 105 | // a 0 in any position is "reset," so we reset to default color 106 | if (newStyle.contains('0')) { 107 | return defaultColor 108 | } 109 | 110 | if (newStyle[0] == '-') { 111 | return "${currentStyle[0]}${newStyle[1]}" 112 | } 113 | 114 | if (newStyle[1] == '-') { 115 | return "${newStyle[0]}${currentStyle[1]}" 116 | } 117 | 118 | return newStyle 119 | } 120 | 121 | private fun getColorFromDCCC(code: Char): Color { 122 | val foundColor = textColors.find { it.charCode == code } 123 | if (foundColor != null) { 124 | foundColor.color 125 | } 126 | 127 | return Color.GRAY.brighter() 128 | } 129 | 130 | private fun trimDCCC(textToTrim: String): String { 131 | val buffer = StringBuilder() 132 | var i = 0 133 | while (i < textToTrim.length) { 134 | if (textToTrim[i] == colorCodeChar) { 135 | if (i < textToTrim.length - 1 && textToTrim[i + 1] == colorCodeChar) { 136 | buffer.append(colorCodeChar) 137 | i += 1 138 | } else if (i < textToTrim.length - 2) { 139 | i += 3 140 | } 141 | } else { 142 | buffer.append(textToTrim[i]) 143 | } 144 | 145 | ++i 146 | } 147 | 148 | return buffer.toString() 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/main/kotlin/dev/bbuck/dragonconsole/ui/PromptPanel.kt: -------------------------------------------------------------------------------- 1 | package dev.bbuck.dragonconsole.ui 2 | 3 | import dev.bbuck.dragonconsole.text.TextColor 4 | import java.awt.BorderLayout 5 | import java.awt.Color 6 | import java.awt.Font 7 | import javax.swing.JPanel 8 | 9 | class PromptPanel(prompt: String, var defaultColor: String) : JPanel() { 10 | var promptLabel: PromptLabel 11 | 12 | init { 13 | promptLabel = PromptLabel(prompt, defaultColor) 14 | promptLabel.setOpaque(false) 15 | setLayout(BorderLayout()) 16 | add(promptLabel, BorderLayout.NORTH) 17 | } 18 | 19 | public fun setPrompt(newPrompt: String) { 20 | promptLabel.setText(newPrompt) 21 | } 22 | 23 | public fun addColor(textColor: TextColor) { 24 | promptLabel.addColor(textColor) 25 | } 26 | 27 | public fun clearColors() { 28 | promptLabel.clearColors() 29 | } 30 | 31 | public fun removeColor(textColor: TextColor) { 32 | promptLabel.removeColor(textColor) 33 | } 34 | 35 | public fun setColorCodeChar(colorCodeChar: Char) { 36 | promptLabel.colorCodeChar = colorCodeChar 37 | } 38 | 39 | public fun getPrompt(): String { 40 | return promptLabel.getText() 41 | } 42 | 43 | public fun setPromptFont(font: Font) { 44 | promptLabel.setFont(font) 45 | promptLabel.revalidate() 46 | promptLabel.repaint() 47 | } 48 | 49 | public fun setPromptForeground(newColor: Color) { 50 | promptLabel.setForeground(newColor) 51 | promptLabel.revalidate() 52 | promptLabel.repaint() 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/resources/com/eleet/dragonconsole/BUILD: -------------------------------------------------------------------------------- 1 | exports_files(["font/dvsm.ttf"]) 2 | 3 | exports_files([ 4 | "resources/ansi", 5 | "resources/colors", 6 | "resources/input", 7 | "resources/l_console", 8 | "resources/l_font", 9 | "resources/logo_b", 10 | "resources/logo_w", 11 | ]) 12 | -------------------------------------------------------------------------------- /src/main/resources/com/eleet/dragonconsole/font/LICENSE: -------------------------------------------------------------------------------- 1 | Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. 2 | Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below) 3 | 4 | Bitstream Vera Fonts Copyright 5 | ------------------------------ 6 | 7 | Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is 8 | a trademark of Bitstream, Inc. 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of the fonts accompanying this license ("Fonts") and associated 12 | documentation files (the "Font Software"), to reproduce and distribute the 13 | Font Software, including without limitation the rights to use, copy, merge, 14 | publish, distribute, and/or sell copies of the Font Software, and to permit 15 | persons to whom the Font Software is furnished to do so, subject to the 16 | following conditions: 17 | 18 | The above copyright and trademark notices and this permission notice shall 19 | be included in all copies of one or more of the Font Software typefaces. 20 | 21 | The Font Software may be modified, altered, or added to, and in particular 22 | the designs of glyphs or characters in the Fonts may be modified and 23 | additional glyphs or characters may be added to the Fonts, only if the fonts 24 | are renamed to names not containing either the words "Bitstream" or the word 25 | "Vera". 26 | 27 | This License becomes null and void to the extent applicable to Fonts or Font 28 | Software that has been modified and is distributed under the "Bitstream 29 | Vera" names. 30 | 31 | The Font Software may be sold as part of a larger software package but no 32 | copy of one or more of the Font Software typefaces may be sold by itself. 33 | 34 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 35 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, 36 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, 37 | TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME 38 | FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING 39 | ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, 40 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 41 | THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE 42 | FONT SOFTWARE. 43 | 44 | Except as contained in this notice, the names of Gnome, the Gnome 45 | Foundation, and Bitstream Inc., shall not be used in advertising or 46 | otherwise to promote the sale, use or other dealings in this Font Software 47 | without prior written authorization from the Gnome Foundation or Bitstream 48 | Inc., respectively. For further information, contact: fonts at gnome dot 49 | org. 50 | 51 | Arev Fonts Copyright 52 | ------------------------------ 53 | 54 | Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. 55 | 56 | Permission is hereby granted, free of charge, to any person obtaining 57 | a copy of the fonts accompanying this license ("Fonts") and 58 | associated documentation files (the "Font Software"), to reproduce 59 | and distribute the modifications to the Bitstream Vera Font Software, 60 | including without limitation the rights to use, copy, merge, publish, 61 | distribute, and/or sell copies of the Font Software, and to permit 62 | persons to whom the Font Software is furnished to do so, subject to 63 | the following conditions: 64 | 65 | The above copyright and trademark notices and this permission notice 66 | shall be included in all copies of one or more of the Font Software 67 | typefaces. 68 | 69 | The Font Software may be modified, altered, or added to, and in 70 | particular the designs of glyphs or characters in the Fonts may be 71 | modified and additional glyphs or characters may be added to the 72 | Fonts, only if the fonts are renamed to names not containing either 73 | the words "Tavmjong Bah" or the word "Arev". 74 | 75 | This License becomes null and void to the extent applicable to Fonts 76 | or Font Software that has been modified and is distributed under the 77 | "Tavmjong Bah Arev" names. 78 | 79 | The Font Software may be sold as part of a larger software package but 80 | no copy of one or more of the Font Software typefaces may be sold by 81 | itself. 82 | 83 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 84 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 85 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 86 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL 87 | TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 88 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 89 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 90 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 91 | OTHER DEALINGS IN THE FONT SOFTWARE. 92 | 93 | Except as contained in this notice, the name of Tavmjong Bah shall not 94 | be used in advertising or otherwise to promote the sale, use or other 95 | dealings in this Font Software without prior written authorization 96 | from Tavmjong Bah. For further information, contact: tavmjong @ free 97 | . fr. 98 | 99 | $Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $ 100 | -------------------------------------------------------------------------------- /src/main/resources/com/eleet/dragonconsole/font/dvsm.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bbuck/DragonConsole/aa68a02b85c095c22565c5322368af880f6ff2b4/src/main/resources/com/eleet/dragonconsole/font/dvsm.ttf -------------------------------------------------------------------------------- /src/main/resources/com/eleet/dragonconsole/resources/ansi: -------------------------------------------------------------------------------- 1 | &00&C--- ANSI Support --&00 2 | 3 | &X-Dragon&x-Console&00 3.0 is compatible with ANSI Color Codes. The &X-Dragon&x-Console&00 class 4 | has two methods that will allow you to convert between &X-Dragon&x-Console&00 Color Codes 5 | (DCCC) and ANSI Color Codes if you so choose. 6 | 7 | &G-FYI:&00 To make an ANSI Color Code you begin with the ESCAPE character ANSI looks 8 | for which is "&C-\033&00" or you could use &R-dev.bbuck.dragonconsole.text.ANSI.&l-ESCAPE&00. 9 | 10 | &G-convertToANSIColors(&l-String&G-)&00 - Converts any DCCCs in the given String to their 11 | valid ANSI counterpart, if no valid counterpart for that color can be found then 12 | it is replaced with "&C-[39;49m&00" which sets the foreground and background to 13 | their defaults. 14 | 15 | &G-convertToDCColors(&l-String&G-)&00 - Converts any ANSI codes in the given String to their 16 | DCCC counterparts, if no DCCC counterpart can be found then the default color 17 | code set in the &X-Dragon&x-Console&00 class will be used. 18 | 19 | &R-- How to Enable and use ANSI Color Codes.&00 20 | 21 | ANSI Color Code usage must be enabled in order for the console to process ANSI 22 | codes and apply them. Enabling ANSI Codes can be done with the 23 | &R-setUseANSIColorCodes(&l-boolean&R-)&00 method of the &X-Dragon&x-Console&00 class. 24 | 25 | Once ANSI Codes have been enabled then the console will process and use ANSI 26 | codes in the Strings sent to &R-append(&l-String&R-)&00. 27 | 28 | &R-- What about Other ANSI Codes?&00 29 | 30 | I plan to continue building upon the ANSI support, as well as the proprietary 31 | &X-Dragon&x-Console&00 scripts and commands to make &X-Dragon&x-Console&00 a useful and easy 32 | to implement Terminal Emulator. 33 | 34 | &r-** IF ANSI CODES ARE ENABLED DCCC CODES WILL NOT BE APPLIED TO TEXT ** 35 | 36 | *** ANSI Codes and DCCCs will ALWAYS be processed out of any String sent to 37 | &R-append(&l-String&R-)&r- regardless if they are enabled or not. This is important to note 38 | because even if ANSI Codes are enabled you must pass "&&&&" to get "&&" as well as 39 | "%%%%" to get "%%" ***&00 40 | -------------------------------------------------------------------------------- /src/main/resources/com/eleet/dragonconsole/resources/colors: -------------------------------------------------------------------------------- 1 | &00&C-- &r-C &y-O &l-L &m-O &r-R &y-S &c-for the &C-Programmer &C-- 2 | &X-Dragon&00Console &00supports color output, and to create the rich output is extremely 3 | simple! When you &R-append &00a String to the console it will process the String for 4 | any color codes and add the String to the document with the proper styles for 5 | each section. 6 | 7 | Let's color a prompt! We'll use &C-"&00prompt@example> &C-" &00and without color you see: 8 | 9 | &00prompt@example> 10 | 11 | &00Which can be kind of boring, but with color we can change that. We'll use the 12 | new prompt with color codes &C-"&00&&rbprompt&&lb@&&Gbexample&&cb> &C-" &00to get: 13 | 14 | &r-prompt&l-@&G-example&C-> 15 | 16 | &00Which is now much easier to denote each separate portion and it pops off the 17 | screen. Are the colors required, of course not, but they make everything look 18 | better if used appropriately. 19 | 20 | So, how exactly do you create a proper color code? Well lets see, a color code 21 | consists of a color code character, a foreground character, and background 22 | character. 23 | 24 | &C-&&FB 25 | 26 | &00The "&C-&&&00" is the default color code character (can be changed with 27 | &R-setColorCodeChar(&l-char&R-)&00) the "&C-F&00" is the Foreground color character 28 | and the "&C-B&00" is the Background color character. By default there are a 29 | number of colors added to the console and you can add anymore that you want 30 | with &R-addTextColor(&l-char&R-, &l-Color&R-)&00. 31 | 32 | Colors that are built in: 33 | &C-Color Name Character Example 34 | &c--------------------------------------------- 35 | &00Red r &r-Red&00 36 | Dark Red R &R-Dark Red&00 37 | Blue l &l-Blue&00 38 | Dark Blue L &L-Dark Blue&00 39 | Cyan c &c-Cyan&00 40 | Dark Cyan C &C-Dark Cyan&00 41 | Green g &g-Green&00 42 | Dark Green G &G-Dark Green&00 43 | Yellow y &y-Yellow&00 44 | Dark Yellow Y &Y-Dark Yellow&00 45 | Magenta m &m-Magenta&00 46 | Dark Magenta M &M-Dark Magenta&00 47 | Gray x &x-Gray&00 48 | Dark Gray X &X-Dark Gray&00 49 | Black b &b-Black&w- (invisible on black background)&00 50 | White w &w-White&b- (invisible on white background)&00 51 | Orange o &o-Orange&00 52 | Dark Orange O &O-Dark Orange&00 53 | Gold d &d-Gold&00 54 | Dark Gold D &D-Dark Gold&00 55 | Purple p &p-Purple&00 56 | Dark Purple P &P-Dark Purple&00 57 | 58 | Colors can also have a specific background like if you wanted to &byhighlight 59 | &00something important. 60 | 61 | In addition to the Built in Color Codes there are two characters that can be 62 | used that do not have a color attached to them and they are "&C-0&00" and "&C--&00". 63 | The "&C-0&00" is used as "&C-&&00&00" which will reset the current style to the 64 | default value. The "&C--&00" is used in place of a color, and it means "&C-carry 65 | over the previous value&00" for whichever spot you leave it. Given that the Color 66 | Code format is "&C-&&FB&00" the code "&C-&&-B&00" translates to "&C-use the previous 67 | foreground color with this new background color&00" and the code "&C-&&F-&00" translates 68 | to "&C-use this new foreground on the previous background color&00." 69 | 70 | That's a brief explanation of color codes and colors.&00 -------------------------------------------------------------------------------- /src/main/resources/com/eleet/dragonconsole/resources/input: -------------------------------------------------------------------------------- 1 | &00&c--- &X-Dragon&x-Console &00Input Script &c---&00 2 | 3 | One of the new features of &X-Dragon&x-Console &003.0 is Input Script, the first in a 4 | series of scriptable text segments that will give the programmer more control 5 | over how text is displayed and handled in the console. 6 | 7 | &R-- What does Input Script Do?&00 8 | 9 | Input Script only works when you are using "&C-Inline Input&00" (which is on by 10 | default) and it allows you to specify where in your output you want input to 11 | start and end and how it should be displayed. There are four ways to set up 12 | input: 13 | 14 | &G-Un-Protected Infinite &00- The user can type from the last line of output until 15 | they choose to stop, pressing enter will cause the Console to read the input and 16 | send it to it's registered CommandProcessor if one has been registered. 17 | 18 | &G-Protected Infinite &00- Functions the same as Un-Protected Infinite however all 19 | text is displayed on screen as "&C-*&00" (by default, this can be changed by calling 20 | the &R-setProtectedCharacter(&l-char&R-)&00 of the &X-Dragon&x-Console class). 21 | 22 | &G-Un-Protected Ranged &00- Ranged Input is input that has a set number of characters. 23 | Ranged Input is also the only input that have more output after the "&C-input area&00" 24 | as Infinite Input ignores anything after the Input Script. Ranged Input can be 25 | useful when designing menu systems. 26 | 27 | &G-Protected Ranged &00- Functions the same as Ranged input, however any input from 28 | the user is output as the protected character which is, by default, a "&C-*&00". 29 | 30 | &R-- What does Input Script Look Like?&00 31 | 32 | Now you know what Input Script does, but what does it look like? Input Script is 33 | formatted as follows 34 | 35 | &C-%%i#+;&00 36 | 37 | Let's break that down and explain each part. The "&C-%%&00" is the &X-Dragon&x-Console 38 | Script character that notifies the console that Script will follow. The "&C-i&00" 39 | tells the console that this is Input Script, the "&C-#&00" is a valid &l-integer&00 that 40 | specifies the maximum range of the input, if the input is Infinite (has no max 41 | range) then you can omit the number. The final character "&C-+&00" tells the console 42 | if this input is protected or not. The "&C-+&00" tells the console to protect this 43 | input, a "&C--&00" tells the console not to protect this input, or you can omit this 44 | character and the console assumes the input should not be protected. 45 | 46 | I hope that helped you better understand Input Script.&00 -------------------------------------------------------------------------------- /src/main/resources/com/eleet/dragonconsole/resources/l_console: -------------------------------------------------------------------------------- 1 | &00Copyright (c) 2010-11 3l33t Software Developers, L.L.C. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/main/resources/com/eleet/dragonconsole/resources/l_font: -------------------------------------------------------------------------------- 1 | &00Fonts are (c) Bitstream &00(see below). DejaVu changes are in public domain. 2 | Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below) 3 | 4 | Bitstream Vera Fonts Copyright 5 | ------------------------------ 6 | 7 | Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is 8 | a trademark of Bitstream, Inc. 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of the fonts accompanying this license ("Fonts") and associated 12 | documentation files (the "Font Software"), to reproduce and distribute the 13 | Font Software, including without limitation the rights to use, copy, merge, 14 | publish, distribute, and/or sell copies of the Font Software, and to permit 15 | persons to whom the Font Software is furnished to do so, subject to the 16 | following conditions: 17 | 18 | The above copyright and trademark notices and this permission notice shall 19 | be included in all copies of one or more of the Font Software typefaces. 20 | 21 | The Font Software may be modified, altered, or added to, and in particular 22 | the designs of glyphs or characters in the Fonts may be modified and 23 | additional glyphs or characters may be added to the Fonts, only if the fonts 24 | are renamed to names not containing either the words "Bitstream" or the word 25 | "Vera". 26 | 27 | This License becomes null and void to the extent applicable to Fonts or Font 28 | Software that has been modified and is distributed under the "Bitstream 29 | Vera" names. 30 | 31 | The Font Software may be sold as part of a larger software package but no 32 | copy of one or more of the Font Software typefaces may be sold by itself. 33 | 34 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 35 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, 36 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, 37 | TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME 38 | FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING 39 | ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, 40 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 41 | THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE 42 | FONT SOFTWARE. 43 | 44 | Except as contained in this notice, the names of Gnome, the Gnome 45 | Foundation, and Bitstream Inc., shall not be used in advertising or 46 | otherwise to promote the sale, use or other dealings in this Font Software 47 | without prior written authorization from the Gnome Foundation or Bitstream 48 | Inc., respectively. For further information, contact: fonts at gnome dot 49 | org. 50 | 51 | Arev Fonts Copyright 52 | ------------------------------ 53 | 54 | Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. 55 | 56 | Permission is hereby granted, free of charge, to any person obtaining 57 | a copy of the fonts accompanying this license ("Fonts") and 58 | associated documentation files (the "Font Software"), to reproduce 59 | and distribute the modifications to the Bitstream Vera Font Software, 60 | including without limitation the rights to use, copy, merge, publish, 61 | distribute, and/or sell copies of the Font Software, and to permit 62 | persons to whom the Font Software is furnished to do so, subject to 63 | the following conditions: 64 | 65 | The above copyright and trademark notices and this permission notice 66 | shall be included in all copies of one or more of the Font Software 67 | typefaces. 68 | 69 | The Font Software may be modified, altered, or added to, and in 70 | particular the designs of glyphs or characters in the Fonts may be 71 | modified and additional glyphs or characters may be added to the 72 | Fonts, only if the fonts are renamed to names not containing either 73 | the words "Tavmjong Bah" or the word "Arev". 74 | 75 | This License becomes null and void to the extent applicable to Fonts 76 | or Font Software that has been modified and is distributed under the 77 | "Tavmjong Bah Arev" names. 78 | 79 | The Font Software may be sold as part of a larger software package but 80 | no copy of one or more of the Font Software typefaces may be sold by 81 | itself. 82 | 83 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 84 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 85 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 86 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL 87 | TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 88 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 89 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 90 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 91 | OTHER DEALINGS IN THE FONT SOFTWARE. 92 | 93 | Except as contained in this notice, the name of Tavmjong Bah shall not 94 | be used in advertising or otherwise to promote the sale, use or other 95 | dealings in this Font Software without prior written authorization 96 | from Tavmjong Bah. For further information, contact: tavmjong @ free 97 | . fr. 98 | 99 | $Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $ 100 | -------------------------------------------------------------------------------- /src/main/resources/com/eleet/dragonconsole/resources/logo_b: -------------------------------------------------------------------------------- 1 | &00 2 | &XbDragon&x-Console &R-is &w-(c) 2010-22 &C-Brandon Buck 3 | &R-Licensed under the &w-MIT License 4 | 5 | &X-8888888b. 6 | 888 "Y88b 7 | 888 888 8 | 888 888 888d888 8888b. .d88b. .d88b. 88888b. 9 | 888 888 888P" "88b d88P"88b d88""88b 888 "88b 10 | 888 888 888 .d888888 888 888 888 888 888 888 11 | 888 .d88P 888 888 888 Y88b 888 Y88..88P 888 888 12 | 8888888P" 888 "Y888888 "Y88888 "Y88P" 888 888 13 | 888 14 | &x- .d8888b. &X-Y8b d88P&x- 888 15 | &x- d88P Y88b &X-"Y88P"&x- 888 16 | 888 888 888 17 | 888 .d88b. 88888b. .d8888b .d88b. 888 .d88b. 18 | 888 d88""88b 888 "88b 88K d88""88b 888 d8P Y8b 19 | 888 888 888 888 888 888 "Y8888b. 888 888 888 88888888 20 | Y88b d88P Y88..88P 888 888 X88 Y88..88P 888 Y8b. 21 | "Y8888P" "Y88P" 888 888 88888P' "Y88P" 888 "Y8888 22 | &R-V E R S I O N &G-3 &w-. &G-1 &w-. &G-0 23 | 24 | &00 25 | -------------------------------------------------------------------------------- /src/main/resources/com/eleet/dragonconsole/resources/logo_w: -------------------------------------------------------------------------------- 1 | &00 2 | &bwDragon&X-Console &R-is &L-(c) 2010-22 &C-Brandon Buck 3 | &R-Licensed under the &L-MIT License 4 | 5 | &b-8888888b. 6 | 888 "Y88b 7 | 888 888 8 | 888 888 888d888 8888b. .d88b. .d88b. 88888b. 9 | 888 888 888P" "88b d88P"88b d88""88b 888 "88b 10 | 888 888 888 .d888888 888 888 888 888 888 888 11 | 888 .d88P 888 888 888 Y88b 888 Y88..88P 888 888 12 | 8888888P" 888 "Y888888 "Y88888 "Y88P" 888 888 13 | 888 14 | &X- .d8888b. &b-Y8b d88P&X- 888 15 | &X- d88P Y88b &b-"Y88P"&X- 888 16 | 888 888 888 17 | 888 .d88b. 88888b. .d8888b .d88b. 888 .d88b. 18 | 888 d88""88b 888 "88b 88K d88""88b 888 d8P Y8b 19 | 888 888 888 888 888 888 "Y8888b. 888 888 888 88888888 20 | Y88b d88P Y88..88P 888 888 X88 Y88..88P 888 Y8b. 21 | "Y8888P" "Y88P" 888 888 88888P' "Y88P" 888 "Y8888 22 | &R-V E R S I O N &G-3 &o-. &G-1 &o-. &G-0 23 | 24 | &00 25 | --------------------------------------------------------------------------------