Feature: ExtraKey in NeoLang
This commit is contained in:
parent
867736afe5
commit
68adad5238
@ -1,10 +1,14 @@
|
||||
extra-key: {
|
||||
version: 10
|
||||
with-default: true
|
||||
|
||||
program: [ "vim", "vi" ]
|
||||
|
||||
key: [
|
||||
"hello",
|
||||
{
|
||||
display: "Ctrl"
|
||||
code: "<CTRL>"
|
||||
with-enter: true
|
||||
},
|
||||
{
|
||||
display: "Esc"
|
||||
|
@ -77,7 +77,6 @@ open class NeoColorScheme {
|
||||
|
||||
fun loadConfigure(file: File): Boolean {
|
||||
val loaderService = ServiceManager.getService<ConfigureService>()
|
||||
|
||||
val configure = loaderService.newLoader(file).loadConfigure()
|
||||
|
||||
if (configure == null) {
|
||||
|
@ -1,12 +1,13 @@
|
||||
package io.neoterm.customize.config.loader
|
||||
|
||||
import io.neoterm.customize.eks.ExtraKeyConfigParser
|
||||
import io.neoterm.customize.eks.NeoExtraKey
|
||||
import io.neolang.runtime.type.NeoLangValue
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.customize.eks.NeoExtraKey
|
||||
import io.neoterm.frontend.config.NeoConfigureFile
|
||||
import io.neoterm.view.eks.button.TextButton
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
@ -15,7 +16,46 @@ class OldExtraKeysConfigureFile(configureFile: File) : NeoConfigureFile(configur
|
||||
override var configVisitor: ConfigVisitor? = null
|
||||
|
||||
override fun parseConfigure(): Boolean {
|
||||
return super.parseConfigure()
|
||||
try {
|
||||
val config = parseOldConfig(BufferedReader(FileReader(configureFile)))
|
||||
return generateVisitor(config)
|
||||
} catch (e: Exception) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateVisitor(config: NeoExtraKey): Boolean {
|
||||
configVisitor = ConfigVisitor()
|
||||
val visitor = configVisitor!!
|
||||
visitor.onStart()
|
||||
visitor.onEnterContext(NeoExtraKey.EKS_META_CONTEXT_NAME)
|
||||
visitor.getCurrentContext()
|
||||
.defineAttribute(NeoExtraKey.EKS_META_VERSION, NeoLangValue(config.version))
|
||||
.defineAttribute(NeoExtraKey.EKS_META_WITH_DEFAULT, NeoLangValue(config.withDefaultKeys))
|
||||
|
||||
// program
|
||||
visitor.onEnterContext(NeoExtraKey.EKS_META_PROGRAM)
|
||||
config.programNames.forEachIndexed { index, program ->
|
||||
visitor.getCurrentContext().defineAttribute(index.toString(), NeoLangValue(program))
|
||||
}
|
||||
visitor.onExitContext()
|
||||
|
||||
// key
|
||||
visitor.onEnterContext(NeoExtraKey.EKS_META_KEY)
|
||||
config.shortcutKeys.forEachIndexed { index, button ->
|
||||
if (button is TextButton) {
|
||||
visitor.onEnterContext(index.toString())
|
||||
visitor.getCurrentContext()
|
||||
.defineAttribute(NeoExtraKey.EKS_META_WITH_ENTER, NeoLangValue(button.withEnter))
|
||||
.defineAttribute(NeoExtraKey.EKS_META_DISPLAY, NeoLangValue(button.buttonText!!))
|
||||
.defineAttribute(NeoExtraKey.EKS_META_CODE, NeoLangValue(button.buttonText!!))
|
||||
visitor.onExitContext()
|
||||
}
|
||||
}
|
||||
visitor.onExitContext()
|
||||
|
||||
visitor.onFinish()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun parseOldConfig(source: BufferedReader): NeoExtraKey {
|
||||
@ -29,13 +69,13 @@ class OldExtraKeysConfigureFile(configureFile: File) : NeoConfigureFile(configur
|
||||
continue
|
||||
}
|
||||
|
||||
if (line.startsWith("version")) {
|
||||
if (line.startsWith(NeoExtraKey.EKS_META_VERSION)) {
|
||||
parseHeader(line, config)
|
||||
} else if (line.startsWith("program")) {
|
||||
} else if (line.startsWith(NeoExtraKey.EKS_META_PROGRAM)) {
|
||||
parseProgram(line, config)
|
||||
} else if (line.startsWith("define")) {
|
||||
parseKeyDefine(line, config)
|
||||
} else if (line.startsWith("with-default")) {
|
||||
} else if (line.startsWith(NeoExtraKey.EKS_META_WITH_DEFAULT)) {
|
||||
parseWithDefault(line, config)
|
||||
}
|
||||
line = source.readLine()
|
||||
@ -51,7 +91,7 @@ class OldExtraKeysConfigureFile(configureFile: File) : NeoConfigureFile(configur
|
||||
}
|
||||
|
||||
private fun parseWithDefault(line: String, config: NeoExtraKey) {
|
||||
val value = line.substring("with-default".length).trim().trimEnd()
|
||||
val value = line.substring(NeoExtraKey.EKS_META_WITH_DEFAULT.length).trim().trimEnd()
|
||||
config.withDefaultKeys = value == "true"
|
||||
}
|
||||
|
||||
@ -69,7 +109,7 @@ class OldExtraKeysConfigureFile(configureFile: File) : NeoConfigureFile(configur
|
||||
}
|
||||
|
||||
private fun parseProgram(line: String, config: NeoExtraKey) {
|
||||
val programNames = line.substring("program".length).trim().trimEnd()
|
||||
val programNames = line.substring(NeoExtraKey.EKS_META_PROGRAM.length).trim().trimEnd()
|
||||
if (programNames.isEmpty()) {
|
||||
return
|
||||
}
|
||||
@ -81,17 +121,13 @@ class OldExtraKeysConfigureFile(configureFile: File) : NeoConfigureFile(configur
|
||||
|
||||
private fun parseHeader(line: String, config: NeoExtraKey) {
|
||||
val version: Int
|
||||
val versionString = line.substring("version".length).trim().trimEnd()
|
||||
val versionString = line.substring(NeoExtraKey.EKS_META_VERSION.length).trim().trimEnd()
|
||||
try {
|
||||
version = Integer.parseInt(versionString)
|
||||
} catch (e: NumberFormatException) {
|
||||
throw RuntimeException("Bad version '$versionString'")
|
||||
}
|
||||
|
||||
if (version > ExtraKeyConfigParser.PARSER_VERSION) {
|
||||
throw RuntimeException("Required version: $version, please upgrade your app")
|
||||
}
|
||||
|
||||
config.version = version
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
package io.neoterm.customize.eks
|
||||
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.frontend.preference.NeoTermPath
|
||||
import io.neoterm.view.eks.ExtraKeysView
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
object ExtraKeyConfigLoader {
|
||||
class ConfiguredExtraKey(val config: NeoExtraKey) : IExtraKey {
|
||||
override fun applyShortcutKeys(extraKeysView: ExtraKeysView) {
|
||||
if (config.withDefaultKeys) {
|
||||
extraKeysView.loadDefaultUserKeys()
|
||||
}
|
||||
for (button in config.shortcutKeys) {
|
||||
extraKeysView.addUserKey(button)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun loadDefinedConfigs(extraKeysManager: ExtraKeysService) {
|
||||
val configDir = File(NeoTermPath.EKS_PATH)
|
||||
configDir.mkdirs()
|
||||
|
||||
val parser = ExtraKeyConfigParser()
|
||||
for (file in configDir.listFiles()) {
|
||||
try {
|
||||
parser.setInput(file)
|
||||
val config = parser.parse()
|
||||
|
||||
// "default" is a reserved program used for default extra keys
|
||||
// see ExtraKeysView.loadDefaultUserKeys()
|
||||
if (config.programNames.contains("default")) {
|
||||
continue
|
||||
}
|
||||
registerConfig(extraKeysManager, config)
|
||||
} catch (e: Exception) {
|
||||
NLog.e("NeoTerm-EKS", "Load $file failed: " + e.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerConfig(extraKeysManager: ExtraKeysService, config: NeoExtraKey) {
|
||||
val shortcutKey = ConfiguredExtraKey(config)
|
||||
for (programName in config.programNames) {
|
||||
extraKeysManager.registerShortcutKeys(programName, shortcutKey)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
package io.neoterm.customize.eks
|
||||
|
||||
import io.neoterm.view.eks.button.TextButton
|
||||
import java.io.*
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ExtraKeyConfigParser {
|
||||
companion object {
|
||||
const val PARSER_VERSION = 5
|
||||
}
|
||||
|
||||
private lateinit var source: BufferedReader
|
||||
|
||||
fun setInput(file: File) {
|
||||
source = BufferedReader(FileReader(file))
|
||||
}
|
||||
|
||||
fun setInput(bufferedReader: BufferedReader) {
|
||||
source = bufferedReader
|
||||
}
|
||||
|
||||
fun setInput(inputStream: BufferedInputStream) {
|
||||
source = BufferedReader(InputStreamReader(inputStream))
|
||||
}
|
||||
|
||||
fun parse(): NeoExtraKey {
|
||||
val config = NeoExtraKey()
|
||||
var line: String? = source.readLine()
|
||||
|
||||
while (line != null) {
|
||||
line = line.trim().trimEnd()
|
||||
if (line.isEmpty() || line.startsWith("#")) {
|
||||
line = source.readLine()
|
||||
continue
|
||||
}
|
||||
|
||||
if (line.startsWith("version")) {
|
||||
parseHeader(line, config)
|
||||
} else if (line.startsWith("program")) {
|
||||
parseProgram(line, config)
|
||||
} else if (line.startsWith("define")) {
|
||||
parseKeyDefine(line, config)
|
||||
} else if (line.startsWith("with-default")) {
|
||||
parseWithDefault(line, config)
|
||||
}
|
||||
line = source.readLine()
|
||||
}
|
||||
|
||||
if (config.version < 0) {
|
||||
throw RuntimeException("Not a valid shortcut config file")
|
||||
}
|
||||
if (config.programNames.size == 0) {
|
||||
throw RuntimeException("At least one program name should be given")
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
private fun parseWithDefault(line: String, config: NeoExtraKey) {
|
||||
val value = line.substring("with-default".length).trim().trimEnd()
|
||||
config.withDefaultKeys = value == "true"
|
||||
}
|
||||
|
||||
private fun parseKeyDefine(line: String, config: NeoExtraKey) {
|
||||
val keyDefine = line.substring("define".length).trim().trimEnd()
|
||||
val keyValues = keyDefine.split(" ")
|
||||
if (keyValues.size < 2) {
|
||||
throw RuntimeException("Bad define")
|
||||
}
|
||||
|
||||
val buttonText = keyValues[0]
|
||||
val withEnter = keyValues[1] == "true"
|
||||
|
||||
config.shortcutKeys.add(TextButton(buttonText, withEnter))
|
||||
}
|
||||
|
||||
private fun parseProgram(line: String, config: NeoExtraKey) {
|
||||
val programNames = line.substring("program".length).trim().trimEnd()
|
||||
if (programNames.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
for (name in programNames.split(" ")) {
|
||||
config.programNames.add(name)
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseHeader(line: String, config: NeoExtraKey) {
|
||||
val version: Int
|
||||
val versionString = line.substring("version".length).trim().trimEnd()
|
||||
try {
|
||||
version = Integer.parseInt(versionString)
|
||||
} catch (e: NumberFormatException) {
|
||||
throw RuntimeException("Bad version '$versionString'")
|
||||
}
|
||||
|
||||
if (version > ExtraKeyConfigParser.PARSER_VERSION) {
|
||||
throw RuntimeException("Required version: $version, please upgrade your app")
|
||||
}
|
||||
|
||||
config.version = version
|
||||
}
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
package io.neoterm.customize.eks
|
||||
|
||||
import io.neoterm.customize.eks.builtin.BuiltinExtraKeys
|
||||
import io.neoterm.frontend.preference.NeoTermPath
|
||||
import io.neoterm.frontend.service.NeoService
|
||||
import io.neoterm.view.eks.ExtraKeysView
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
@ -47,7 +48,13 @@ class ExtraKeysService : NeoService {
|
||||
}
|
||||
|
||||
private fun checkForFiles() {
|
||||
BuiltinExtraKeys.registerAll()
|
||||
ExtraKeyConfigLoader.loadDefinedConfigs(this)
|
||||
// TODO: Builtin keys
|
||||
loadConfigure()
|
||||
}
|
||||
|
||||
private fun loadConfigure() {
|
||||
val configDir = File(NeoTermPath.EKS_PATH)
|
||||
configDir.mkdirs()
|
||||
// TODO: Load configure.
|
||||
}
|
||||
}
|
@ -1,13 +1,90 @@
|
||||
package io.neoterm.customize.eks
|
||||
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.customize.config.ConfigureService
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.frontend.service.ServiceManager
|
||||
import io.neoterm.view.eks.button.IExtraButton
|
||||
import io.neoterm.view.eks.button.TextButton
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class NeoExtraKey {
|
||||
var version: Int = -1
|
||||
companion object {
|
||||
const val EKS_META_CONTEXT_NAME = "extra-key"
|
||||
|
||||
const val EKS_META_PROGRAM = "program"
|
||||
const val EKS_META_KEY = "key"
|
||||
const val EKS_META_WITH_DEFAULT = "with-default"
|
||||
const val EKS_META_WITH_ENTER = "with-enter"
|
||||
const val EKS_META_DISPLAY = "display"
|
||||
const val EKS_META_CODE = "code"
|
||||
const val EKS_META_VERSION = "version"
|
||||
|
||||
val EKS_META_CONTEXT_PATH = arrayOf(EKS_META_CONTEXT_NAME)
|
||||
}
|
||||
|
||||
var version: Int = 0
|
||||
val programNames: MutableList<String> = mutableListOf()
|
||||
val shortcutKeys: MutableList<IExtraButton> = mutableListOf()
|
||||
var withDefaultKeys: Boolean = true
|
||||
|
||||
fun loadConfigure(file: File): Boolean {
|
||||
val loaderService = ServiceManager.getService<ConfigureService>()
|
||||
val configure = loaderService.newLoader(file).loadConfigure()
|
||||
|
||||
if (configure == null) {
|
||||
NLog.e("ExtraKey", "Failed to load extra key config: ${file.absolutePath}")
|
||||
return false
|
||||
}
|
||||
|
||||
val visitor = configure.getVisitor()
|
||||
|
||||
// program
|
||||
val programArray = visitor.getArray(EKS_META_CONTEXT_PATH, EKS_META_PROGRAM)
|
||||
if (programArray.isEmpty()) {
|
||||
NLog.e("ExtraKey", "Failed to load extra key config: ${file.absolutePath}: Extra Key must have programs attribute")
|
||||
return false
|
||||
}
|
||||
|
||||
programArray.forEach {
|
||||
if (!it.isBlock()) {
|
||||
programNames.add(it.eval().asString())
|
||||
}
|
||||
}
|
||||
|
||||
// key
|
||||
val keyArray = visitor.getArray(EKS_META_CONTEXT_PATH, EKS_META_KEY)
|
||||
keyArray.takeWhile { it.isBlock() }
|
||||
.forEach {
|
||||
val display = it.eval(EKS_META_DISPLAY)
|
||||
val code = it.eval(EKS_META_CODE)
|
||||
if (!code.isValid()) {
|
||||
NLog.e("ExtraKey", "Failed to load extra key config: ${file.absolutePath}: Key must have a code")
|
||||
return false
|
||||
}
|
||||
|
||||
val codeText = code.asString()
|
||||
val displayText = if (display.isValid()) display.asString() else codeText
|
||||
val withEnter = it.eval(EKS_META_WITH_ENTER)
|
||||
val withEnterBoolean = withEnter.asString() == "true"
|
||||
|
||||
val button = TextButton(codeText, withEnterBoolean)
|
||||
button.displayText = displayText
|
||||
shortcutKeys.add(button)
|
||||
}
|
||||
|
||||
// We must cal toDouble() before toInt()
|
||||
// Because in NeoLang, numbers are default convert into Double
|
||||
version = getMetaByVisitor(visitor, EKS_META_VERSION)?.toDouble()?.toInt() ?: 0
|
||||
withDefaultKeys = "true" == getMetaByVisitor(visitor, EKS_META_WITH_DEFAULT)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getMetaByVisitor(visitor: ConfigVisitor, metaName: String): String? {
|
||||
val value = visitor.getAttribute(EKS_META_CONTEXT_PATH, metaName)
|
||||
return if (value.isValid()) value.asString() else null
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
package io.neoterm.customize.eks.builtin
|
||||
|
||||
import io.neoterm.frontend.preference.NeoTermPath
|
||||
import io.neoterm.customize.eks.ExtraKeyConfigParser
|
||||
import io.neoterm.utils.FileUtils
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
object BuiltinExtraKeys {
|
||||
private const val vimKeys = "version ${ExtraKeyConfigParser.PARSER_VERSION}\n" +
|
||||
"program vim neovim vi\n" +
|
||||
"define dd true\n" +
|
||||
"define :x true\n" +
|
||||
"define :w true\n" +
|
||||
"define :q true\n"
|
||||
|
||||
private const val moreKeys = "version ${ExtraKeyConfigParser.PARSER_VERSION}\n" +
|
||||
"program more less\n" +
|
||||
"define R false\n" +
|
||||
"define Q false\n"
|
||||
|
||||
fun registerAll() {
|
||||
val configDir = File(NeoTermPath.EKS_PATH)
|
||||
configDir.mkdirs()
|
||||
|
||||
val vimFile = File(configDir, "vim.eks")
|
||||
if (!vimFile.exists()) {
|
||||
FileUtils.writeFile(vimFile, vimKeys.toByteArray())
|
||||
}
|
||||
|
||||
val moreFile = File(configDir, "more-less.eks")
|
||||
if (!moreFile.exists()) {
|
||||
FileUtils.writeFile(moreFile, moreKeys.toByteArray())
|
||||
}
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package io.neoterm.view.eks
|
||||
|
||||
import io.neoterm.customize.eks.ExtraKeyConfigParser
|
||||
import io.neoterm.frontend.preference.NeoTermPath
|
||||
import io.neoterm.utils.FileUtils
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
object ExtraKeysUtils {
|
||||
fun generateDefaultFile(defaultFile: File) {
|
||||
val DEFAULT_FILE_CONTENT = "version " + ExtraKeyConfigParser.PARSER_VERSION + "\n" +
|
||||
"program default\n" +
|
||||
"define - false\n" +
|
||||
"define / false\n" +
|
||||
"define \\ false\n" +
|
||||
"define | false\n" +
|
||||
"define $ false\n" +
|
||||
"define < false\n" +
|
||||
"define > false\n"
|
||||
FileUtils.writeFile(defaultFile, DEFAULT_FILE_CONTENT.toByteArray())
|
||||
}
|
||||
|
||||
fun getDefaultFile(): File {
|
||||
val defaultFile = File(NeoTermPath.EKS_DEFAULT_FILE)
|
||||
if (!defaultFile.exists()) {
|
||||
generateDefaultFile(defaultFile)
|
||||
}
|
||||
return defaultFile
|
||||
}
|
||||
}
|
@ -7,7 +7,6 @@ import android.view.*
|
||||
import android.widget.GridLayout
|
||||
import android.widget.LinearLayout
|
||||
import io.neoterm.R
|
||||
import io.neoterm.customize.eks.ExtraKeyConfigParser
|
||||
import io.neoterm.frontend.preference.NeoPreference
|
||||
import io.neoterm.ui.term.event.ToggleImeEvent
|
||||
import io.neoterm.view.eks.button.ControlButton
|
||||
@ -113,17 +112,18 @@ class ExtraKeysView(context: Context, attrs: AttributeSet) : LinearLayout(contex
|
||||
}
|
||||
|
||||
fun loadDefaultUserKeys() {
|
||||
val defaultFile = ExtraKeysUtils.getDefaultFile()
|
||||
// val defaultFile = ExtraKeysUtils.getDefaultFile()
|
||||
clearUserKeys()
|
||||
|
||||
try {
|
||||
val parser = ExtraKeyConfigParser()
|
||||
parser.setInput(defaultFile)
|
||||
val config = parser.parse()
|
||||
userKeys.addAll(config.shortcutKeys)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
// TODO: loadDefaultUserKeys
|
||||
// try {
|
||||
// val parser = ExtraKeyConfigParser()
|
||||
// parser.setInput(defaultFile)
|
||||
// val config = parser.parse()
|
||||
// userKeys.addAll(config.shortcutKeys)
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
}
|
||||
|
||||
fun updateButtons() {
|
||||
@ -205,7 +205,7 @@ class ExtraKeysView(context: Context, attrs: AttributeSet) : LinearLayout(contex
|
||||
outerButton.layoutParams = param
|
||||
outerButton.maxLines = 1
|
||||
outerButton.typeface = typeface
|
||||
outerButton.text = extraButton.buttonText
|
||||
outerButton.text = extraButton.displayText
|
||||
outerButton.setPadding(0, 0, 0, 0)
|
||||
outerButton.setTextColor(IExtraButton.NORMAL_TEXT_COLOR)
|
||||
outerButton.setAllCaps(false)
|
||||
|
@ -1,210 +0,0 @@
|
||||
package io.neoterm.view.eks
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
import android.util.AttributeSet
|
||||
import android.view.Gravity
|
||||
import android.view.HapticFeedbackConstants
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.HorizontalScrollView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ToggleButton
|
||||
|
||||
import java.io.File
|
||||
import java.util.ArrayList
|
||||
|
||||
import io.neoterm.customize.eks.ExtraKeyConfigParser
|
||||
import io.neoterm.frontend.preference.NeoTermPath
|
||||
import io.neoterm.utils.FileUtils
|
||||
import io.neoterm.view.eks.button.ControlButton
|
||||
import io.neoterm.view.eks.button.IExtraButton
|
||||
import io.neoterm.view.eks.button.StatedControlButton
|
||||
|
||||
/**
|
||||
* A view showing extra keys (such as Escape, Ctrl, Alt) not normally available on an Android soft
|
||||
* keyboard.
|
||||
*/
|
||||
class ScrollExtraKeysView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
|
||||
|
||||
private var builtinExtraKeys: MutableList<IExtraButton>? = null
|
||||
private var userDefinedExtraKeys: MutableList<IExtraButton>? = null
|
||||
|
||||
private val lineOne: LinearLayout
|
||||
private val lineTwo: LinearLayout
|
||||
private var typeface: Typeface? = null
|
||||
|
||||
init {
|
||||
gravity = Gravity.TOP
|
||||
orientation = LinearLayout.VERTICAL
|
||||
|
||||
val scrollOne = HorizontalScrollView(context)
|
||||
val scrollTwo = HorizontalScrollView(context)
|
||||
lineOne = initLine(scrollOne)
|
||||
lineTwo = initLine(scrollTwo)
|
||||
addView(scrollOne)
|
||||
addView(scrollTwo)
|
||||
|
||||
loadBuiltinKeys()
|
||||
loadUserKeys()
|
||||
updateButtons()
|
||||
}
|
||||
|
||||
private fun initLine(scroll: HorizontalScrollView): LinearLayout {
|
||||
val line = LinearLayout(context)
|
||||
line.gravity = Gravity.START
|
||||
line.orientation = LinearLayout.HORIZONTAL
|
||||
|
||||
scroll.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f)
|
||||
scroll.isFillViewport = true
|
||||
scroll.isHorizontalScrollBarEnabled = false
|
||||
scroll.addView(line)
|
||||
return line
|
||||
}
|
||||
|
||||
fun readControlButton(): Boolean {
|
||||
return CTRL.readState()
|
||||
}
|
||||
|
||||
fun readAltButton(): Boolean {
|
||||
return ALT.readState()
|
||||
}
|
||||
|
||||
fun addUserKey(button: IExtraButton) {
|
||||
addKeyButton(userDefinedExtraKeys, button)
|
||||
}
|
||||
|
||||
fun addBuiltinKey(button: IExtraButton) {
|
||||
addKeyButton(builtinExtraKeys, button)
|
||||
}
|
||||
|
||||
fun clearUserKeys() {
|
||||
userDefinedExtraKeys!!.clear()
|
||||
}
|
||||
|
||||
fun loadUserKeys() {
|
||||
userDefinedExtraKeys = ArrayList<IExtraButton>(8)
|
||||
val defaultFile = File(NeoTermPath.EKS_DEFAULT_FILE)
|
||||
if (!defaultFile.exists()) {
|
||||
generateDefaultFile(defaultFile)
|
||||
}
|
||||
|
||||
clearUserKeys()
|
||||
try {
|
||||
val parser = ExtraKeyConfigParser()
|
||||
parser.setInput(defaultFile)
|
||||
val config = parser.parse()
|
||||
userDefinedExtraKeys!!.addAll(config.shortcutKeys)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun loadBuiltinKeys() {
|
||||
builtinExtraKeys = ArrayList<IExtraButton>(7)
|
||||
builtinExtraKeys!!.clear()
|
||||
builtinExtraKeys!!.add(ESC)
|
||||
builtinExtraKeys!!.add(CTRL)
|
||||
builtinExtraKeys!!.add(ALT)
|
||||
builtinExtraKeys!!.add(TAB)
|
||||
builtinExtraKeys!!.add(ARROW_UP)
|
||||
builtinExtraKeys!!.add(ARROW_DOWN)
|
||||
builtinExtraKeys!!.add(ARROW_LEFT)
|
||||
builtinExtraKeys!!.add(ARROW_RIGHT)
|
||||
builtinExtraKeys!!.add(PAGE_UP)
|
||||
builtinExtraKeys!!.add(PAGE_DOWN)
|
||||
builtinExtraKeys!!.add(HOME)
|
||||
builtinExtraKeys!!.add(END)
|
||||
}
|
||||
|
||||
fun updateButtons() {
|
||||
lineOne.removeAllViews()
|
||||
lineTwo.removeAllViews()
|
||||
for (extraButton in userDefinedExtraKeys!!) {
|
||||
addKeyButton(lineOne, extraButton)
|
||||
}
|
||||
for (extraButton in builtinExtraKeys!!) {
|
||||
addKeyButton(lineTwo, extraButton)
|
||||
}
|
||||
}
|
||||
|
||||
fun setTextColor(textColor: Int) {
|
||||
NORMAL_TEXT_COLOR = textColor
|
||||
updateButtons()
|
||||
}
|
||||
|
||||
fun setTypeface(typeface: Typeface?) {
|
||||
this.typeface = typeface
|
||||
updateButtons()
|
||||
}
|
||||
|
||||
private fun addKeyButton(buttons: MutableList<IExtraButton>?, button: IExtraButton) {
|
||||
if (buttons != null && !buttons.contains(button)) {
|
||||
buttons.add(button)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addKeyButton(contentView: LinearLayout, extraButton: IExtraButton) {
|
||||
val button: Button
|
||||
if (extraButton is StatedControlButton) {
|
||||
val btn = extraButton
|
||||
val toggleButton = ToggleButton(context, null, android.R.attr.buttonBarButtonStyle)
|
||||
btn.toggleButton = toggleButton
|
||||
button = toggleButton
|
||||
|
||||
button.setClickable(true)
|
||||
if (btn.initState) {
|
||||
btn.toggleButton!!.isChecked = true
|
||||
btn.toggleButton!!.setTextColor(SELECTED_TEXT_COLOR)
|
||||
}
|
||||
} else {
|
||||
button = Button(context, null, android.R.attr.buttonBarButtonStyle)
|
||||
}
|
||||
|
||||
button.typeface = typeface
|
||||
button.text = extraButton.buttonText
|
||||
button.setTextColor(NORMAL_TEXT_COLOR)
|
||||
button.setAllCaps(false)
|
||||
|
||||
button.setOnClickListener {
|
||||
button.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP)
|
||||
val root = rootView
|
||||
extraButton.onClick(root)
|
||||
}
|
||||
contentView.addView(button)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
val CTRL = StatedControlButton(IExtraButton.KEY_CTRL)
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
val ALT = StatedControlButton(IExtraButton.KEY_ALT)
|
||||
val ESC = ControlButton(IExtraButton.KEY_ESC)
|
||||
val TAB = ControlButton(IExtraButton.KEY_TAB)
|
||||
val PAGE_UP = ControlButton(IExtraButton.KEY_PAGE_UP)
|
||||
val PAGE_DOWN = ControlButton(IExtraButton.KEY_PAGE_DOWN)
|
||||
val HOME = ControlButton(IExtraButton.KEY_HOME)
|
||||
val END = ControlButton(IExtraButton.KEY_END)
|
||||
val ARROW_UP = ControlButton(IExtraButton.KEY_ARROW_UP)
|
||||
val ARROW_DOWN = ControlButton(IExtraButton.KEY_ARROW_DOWN)
|
||||
val ARROW_LEFT = ControlButton(IExtraButton.KEY_ARROW_LEFT)
|
||||
val ARROW_RIGHT = ControlButton(IExtraButton.KEY_ARROW_RIGHT)
|
||||
|
||||
val DEFAULT_FILE_CONTENT = "version " + ExtraKeyConfigParser.PARSER_VERSION + "\n" +
|
||||
"program default\n" +
|
||||
"define - false\n" +
|
||||
"define / false\n" +
|
||||
"define | false\n" +
|
||||
"define $ false\n" +
|
||||
"define < false\n" +
|
||||
"define > false\n"
|
||||
|
||||
var NORMAL_TEXT_COLOR = 0xFFFFFFFF.toInt()
|
||||
var SELECTED_TEXT_COLOR = 0xFF80DEEA.toInt()
|
||||
|
||||
private fun generateDefaultFile(defaultFile: File) {
|
||||
FileUtils.writeFile(defaultFile, DEFAULT_FILE_CONTENT.toByteArray())
|
||||
}
|
||||
}
|
||||
}
|
@ -4,8 +4,4 @@ package io.neoterm.view.eks.button
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
open class ControlButton(text: String) : TextButton(text, false) {
|
||||
init {
|
||||
buttonText = text
|
||||
}
|
||||
}
|
||||
open class ControlButton(text: String) : TextButton(text, false)
|
||||
|
@ -16,6 +16,7 @@ import io.neoterm.view.TerminalView
|
||||
abstract class IExtraButton : View.OnClickListener {
|
||||
|
||||
var buttonText: String? = null
|
||||
var displayText: String? = null
|
||||
|
||||
abstract override fun onClick(view: View)
|
||||
|
||||
@ -25,7 +26,7 @@ abstract class IExtraButton : View.OnClickListener {
|
||||
val KEY_ESC = "Esc"
|
||||
val KEY_TAB = "Tab"
|
||||
val KEY_CTRL = "Ctrl"
|
||||
val KEY_ALT = "Alt"
|
||||
val KEY_ALT = "Alt"
|
||||
val KEY_PAGE_UP = "PgUp"
|
||||
val KEY_PAGE_DOWN = "PgDn"
|
||||
val KEY_HOME = "Home"
|
||||
|
@ -10,10 +10,11 @@ import android.widget.Button
|
||||
*/
|
||||
|
||||
open class TextButton @JvmOverloads constructor(text: String, withEnter: Boolean = false) : IExtraButton() {
|
||||
private var withEnter = false
|
||||
var withEnter = false
|
||||
|
||||
init {
|
||||
this.buttonText = text
|
||||
this.displayText = text
|
||||
this.withEnter = withEnter
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
package io.neoterm
|
||||
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.customize.color.NeoColorScheme
|
||||
import io.neoterm.customize.config.ConfigureService
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.customize.eks.NeoExtraKey
|
||||
import io.neoterm.frontend.config.NeoConfigureFile
|
||||
import io.neoterm.frontend.service.ServiceManager
|
||||
import org.junit.Test
|
||||
@ -41,21 +42,14 @@ class ConfigureFileTest {
|
||||
|
||||
@Test
|
||||
fun extraKeyConfigureTest() {
|
||||
val visitor = parseConfigure("NeoLang/example/extra-key.nl")
|
||||
if (visitor != null) {
|
||||
val programs = visitor.getArray(arrayOf("extra-key"), "program")
|
||||
programs.forEachIndexed { index, element ->
|
||||
println("program[$index]: ${element.eval().asString()}")
|
||||
}
|
||||
try {
|
||||
ServiceManager.registerService(ConfigureService::class.java)
|
||||
} catch (ignore: Throwable) {
|
||||
}
|
||||
|
||||
val keys = visitor.getArray(arrayOf("extra-key"), "key")
|
||||
keys.forEachIndexed { index, element ->
|
||||
if (element.isBlock()) {
|
||||
println("key[$index]: " +
|
||||
"display: ${element.eval("display").asString()}, " +
|
||||
"code: ${element.eval("code").asString()}")
|
||||
}
|
||||
}
|
||||
val extraKey = NeoExtraKey()
|
||||
if (extraKey.loadConfigure(File("NeoLang/example/extra-key.nl"))) {
|
||||
println(extraKey)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user