mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-09 10:04:05 +09:00
working cangjie IME implementation
This commit is contained in:
318
assets/keylayout/zh_cn_cangjie5.ime
Normal file
318
assets/keylayout/zh_cn_cangjie5.ime
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
let states = {"keylayouts":[[""],[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
["0",")"],
|
||||||
|
["1","!"],
|
||||||
|
["2","@"],
|
||||||
|
["3","#"],
|
||||||
|
["4","¥"],
|
||||||
|
["5","%"],
|
||||||
|
["6","…"],
|
||||||
|
["7","&"],
|
||||||
|
["8","×"],
|
||||||
|
["9","("],
|
||||||
|
["*"],
|
||||||
|
["#"],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
["a","A"],
|
||||||
|
["b","B"],
|
||||||
|
["c","C"],
|
||||||
|
["d","D"],
|
||||||
|
["e","E"],
|
||||||
|
["f","F"],
|
||||||
|
["g","G"],
|
||||||
|
["h","H"],
|
||||||
|
["i","I"],
|
||||||
|
["j","J"],
|
||||||
|
["k","K"],
|
||||||
|
["l","L"],
|
||||||
|
["m","M"],
|
||||||
|
["n","N"],
|
||||||
|
["o","O"],
|
||||||
|
["p","P"],
|
||||||
|
["q","Q"],
|
||||||
|
["r","R"],
|
||||||
|
["s","S"],
|
||||||
|
["t","T"],
|
||||||
|
["u","U"],
|
||||||
|
["v","V"],
|
||||||
|
["w","W"],
|
||||||
|
["x","X"],
|
||||||
|
["y","Y"],
|
||||||
|
["z","Z"],
|
||||||
|
[",","《"],
|
||||||
|
["。","》"],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[" ", " "],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
["\n"],
|
||||||
|
["\x08"],
|
||||||
|
["·","~"],
|
||||||
|
["-","—"],
|
||||||
|
["=","+"],
|
||||||
|
["「","{"],
|
||||||
|
["」","}"],
|
||||||
|
["、","|"],
|
||||||
|
[";",":"],
|
||||||
|
["'",'"'],
|
||||||
|
["/","?"],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
["0"],
|
||||||
|
["1"],
|
||||||
|
["2"],
|
||||||
|
["3"],
|
||||||
|
["4"],
|
||||||
|
["5"],
|
||||||
|
["6"],
|
||||||
|
["7"],
|
||||||
|
["8"],
|
||||||
|
["9"],
|
||||||
|
["/"],
|
||||||
|
["*"],
|
||||||
|
["-"],
|
||||||
|
["+"],
|
||||||
|
["."],
|
||||||
|
["."],
|
||||||
|
["\n"],
|
||||||
|
["="],
|
||||||
|
["("],
|
||||||
|
[")"],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined]
|
||||||
|
],
|
||||||
|
"dict":IMEProvider.requestDictionary("cj5-sc.han"),
|
||||||
|
"code":0, //0: not composing, 1: composing (has candidates), 2: composing (no candidates)
|
||||||
|
"buf":"",
|
||||||
|
"candidates":""/*comma-separated values*/}
|
||||||
|
let reset = () => {
|
||||||
|
states.code = 0
|
||||||
|
states.buf = ""
|
||||||
|
states.candidates = ""
|
||||||
|
}
|
||||||
|
let getCandidatesUsingBuf = () => {
|
||||||
|
states.candidates = states.dict.get(states.buf) // comma-separated values
|
||||||
|
states.code = 1 + (states.candidates.length == 0)
|
||||||
|
// console.log(`cangjie in, buf: ${states.buf}, candidates: ${states.candidates}`)
|
||||||
|
return `${states.buf},${states.candidates}`
|
||||||
|
}
|
||||||
|
return Object.freeze({"n":"五仓简体 Qwerty","states":states,"c":"CuriousTo\uA75Bvald, 倉頡之友 。馬來西亞 http://www.chinesecj.com",
|
||||||
|
// return: [displayed output, composed output]
|
||||||
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
|
let layer = 1*shiftin// + 2*altgrin
|
||||||
|
|
||||||
|
let cjkey = states.keylayouts[headkey][layer]
|
||||||
|
let cjkeyAsc = cjkey.codePointAt(0)
|
||||||
|
|
||||||
|
if (states.code == 1 && 48 <= cjkeyAsc && cjkeyAsc <= 57) {
|
||||||
|
let raw = ''+states.buf
|
||||||
|
let selection = states.candidates.split(',')[cjkeyAsc - 49]
|
||||||
|
reset()
|
||||||
|
return ['', selection || raw]
|
||||||
|
}
|
||||||
|
else if (1 == states.code && " " == cjkey) {
|
||||||
|
let ret = (1 == states.code) ? states.candidates[0] : (''+states.buf)
|
||||||
|
reset()
|
||||||
|
return ['', ret]
|
||||||
|
}
|
||||||
|
else if (states.code < 2 && states.buf.length < 5 && 97 <= cjkeyAsc && cjkeyAsc <= 122 || cjkeyAsc == 42) {
|
||||||
|
states.buf += cjkey
|
||||||
|
return [getCandidatesUsingBuf(), '']
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let ret = ''+states.buf+cjkey
|
||||||
|
reset()
|
||||||
|
return ['', ret]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"backspace":()=>{
|
||||||
|
if (states.buf.length <= 1) {
|
||||||
|
reset()
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
states.buf = states.buf.substring(0, states.buf.length - 1)
|
||||||
|
return getCandidatesUsingBuf()
|
||||||
|
},
|
||||||
|
"end":()=>{
|
||||||
|
let ret = (1 == states.code) ? states.candidates[0] : (''+states.buf)
|
||||||
|
reset()
|
||||||
|
return ret
|
||||||
|
},
|
||||||
|
"reset":()=>{ reset() },
|
||||||
|
"composing":()=>(states.code!=0),
|
||||||
|
"maxCandidates":()=>10
|
||||||
|
})
|
||||||
@@ -4,16 +4,16 @@ let states = {"keylayouts":[[""],[undefined],
|
|||||||
[undefined],
|
[undefined],
|
||||||
[undefined],
|
[undefined],
|
||||||
[undefined],
|
[undefined],
|
||||||
["0",")"],
|
["0",")"],
|
||||||
["1","!"],
|
["1","!"],
|
||||||
["2","@"],
|
["2","@"],
|
||||||
["3","#"],
|
["3","#"],
|
||||||
["4","$"],
|
["4","¥"],
|
||||||
["5","%"],
|
["5","%"],
|
||||||
["6","^"],
|
["6","…"],
|
||||||
["7","&"],
|
["7","&"],
|
||||||
["8","*"],
|
["8","×"],
|
||||||
["9","("],
|
["9","("],
|
||||||
["*"],
|
["*"],
|
||||||
["#"],
|
["#"],
|
||||||
[undefined],
|
[undefined],
|
||||||
@@ -52,26 +52,26 @@ let states = {"keylayouts":[[""],[undefined],
|
|||||||
["x","X"],
|
["x","X"],
|
||||||
["y","Y"],
|
["y","Y"],
|
||||||
["z","Z"],
|
["z","Z"],
|
||||||
[",","<"],
|
[",","《"],
|
||||||
[".",">"],
|
["。","》"],
|
||||||
[undefined],
|
[undefined],
|
||||||
[undefined],
|
[undefined],
|
||||||
[undefined],
|
[undefined],
|
||||||
[undefined],
|
[undefined],
|
||||||
[undefined],
|
[undefined],
|
||||||
[" "],
|
[" ", " "],
|
||||||
[undefined],
|
[undefined],
|
||||||
[undefined],
|
[undefined],
|
||||||
[undefined],
|
[undefined],
|
||||||
["\n"],
|
["\n"],
|
||||||
["\x08"],
|
["\x08"],
|
||||||
["`","~"],
|
["·","~"],
|
||||||
["-","_"],
|
["-","—"],
|
||||||
["=","+"],
|
["=","+"],
|
||||||
["[","{"],
|
["「","{"],
|
||||||
["]","}"],
|
["」","}"],
|
||||||
["\\","|"],
|
["、","|"],
|
||||||
[";",":"],
|
[";",":"],
|
||||||
["'",'"'],
|
["'",'"'],
|
||||||
["/","?"],
|
["/","?"],
|
||||||
[undefined],
|
[undefined],
|
||||||
@@ -263,8 +263,12 @@ let reset = () => {
|
|||||||
states.buf = ""
|
states.buf = ""
|
||||||
states.candidates = ""
|
states.candidates = ""
|
||||||
}
|
}
|
||||||
//let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" : `\\u${buf[i].codePointAt(0).toString(16).toUpperCase()}`).join(' ')
|
let getCandidatesUsingBuf = () => {
|
||||||
let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" : `${buf[i]}`).join(' ')
|
states.candidates = states.dict.get(states.buf) // comma-separated values
|
||||||
|
states.code = 1 + (states.candidates.length == 0)
|
||||||
|
// console.log(`cangjie in, buf: ${states.buf}, candidates: ${states.candidates}`)
|
||||||
|
return `${states.buf},${states.candidates}`
|
||||||
|
}
|
||||||
return Object.freeze({"n":"五倉正體 Qwerty","states":states,"c":"CuriousTo\uA75Bvald, 倉頡之友 。馬來西亞 http://www.chinesecj.com",
|
return Object.freeze({"n":"五倉正體 Qwerty","states":states,"c":"CuriousTo\uA75Bvald, 倉頡之友 。馬來西亞 http://www.chinesecj.com",
|
||||||
// return: [displayed output, composed output]
|
// return: [displayed output, composed output]
|
||||||
"accept":(headkey,shiftin,altgrin)=>{
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
@@ -279,31 +283,32 @@ return Object.freeze({"n":"五倉正體 Qwerty","states":states,"c":"CuriousTo\u
|
|||||||
reset()
|
reset()
|
||||||
return ['', selection || raw]
|
return ['', selection || raw]
|
||||||
}
|
}
|
||||||
else if (97 <= cjkeyAsc && cjkeyAsc <= 122 || cjkeyAsc == 42) {
|
else if (1 == states.code && " " == cjkey) {
|
||||||
|
let ret = (1 == states.code) ? states.candidates[0] : (''+states.buf)
|
||||||
|
reset()
|
||||||
|
return ['', ret]
|
||||||
|
}
|
||||||
|
else if (states.code < 2 && states.buf.length < 5 && 97 <= cjkeyAsc && cjkeyAsc <= 122 || cjkeyAsc == 42) {
|
||||||
states.buf += cjkey
|
states.buf += cjkey
|
||||||
|
return [getCandidatesUsingBuf(), '']
|
||||||
states.candidates = states.dict.get(states.buf) // comma-separated values
|
|
||||||
states.code = 1 + (states.candidates.length == 0)
|
|
||||||
|
|
||||||
console.log(`cangjie in, buf: ${states.buf}, candidates: ${states.candidates}`)
|
|
||||||
|
|
||||||
return [`${states.buf},${states.candidates}`, '']
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
states.code = 0
|
let ret = ''+states.buf+cjkey
|
||||||
return ['', ''+states.buf+cjkey]
|
reset()
|
||||||
|
return ['', ret]
|
||||||
}
|
}
|
||||||
|
|
||||||
return ['', cjkey]
|
|
||||||
},
|
},
|
||||||
"backspace":()=>{
|
"backspace":()=>{
|
||||||
|
if (states.buf.length <= 1) {
|
||||||
|
reset()
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
states.buf = states.buf.substring(0, states.buf.length - 1)
|
||||||
return ''
|
return getCandidatesUsingBuf()
|
||||||
},
|
},
|
||||||
"end":()=>{
|
"end":()=>{
|
||||||
// console.log(`end composing`)
|
let ret = (1 == states.code) ? states.candidates[0] : (''+states.buf)
|
||||||
let ret = ''+states.buf
|
|
||||||
reset()
|
reset()
|
||||||
return ret
|
return ret
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -56,12 +56,12 @@ object IME {
|
|||||||
init {
|
init {
|
||||||
context.getBindings("js").putMember("IMEProvider", IMEProviderDelegate(this))
|
context.getBindings("js").putMember("IMEProvider", IMEProviderDelegate(this))
|
||||||
|
|
||||||
File(KEYLAYOUT_DIR).listFiles { file, s -> s.endsWith(".$KEYLAYOUT_EXTENSION") }.forEach {
|
File(KEYLAYOUT_DIR).listFiles { file, s -> s.endsWith(".$KEYLAYOUT_EXTENSION") }.sortedBy { it.name }.forEach {
|
||||||
printdbg(this, "Registering Low layer ${it.nameWithoutExtension.lowercase()}")
|
printdbg(this, "Registering Low layer ${it.nameWithoutExtension.lowercase()}")
|
||||||
lowLayers[it.nameWithoutExtension.lowercase()] = parseKeylayoutFile(it)
|
lowLayers[it.nameWithoutExtension.lowercase()] = parseKeylayoutFile(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
File(KEYLAYOUT_DIR).listFiles { file, s -> s.endsWith(".$IME_EXTENSION") }.forEach {
|
File(KEYLAYOUT_DIR).listFiles { file, s -> s.endsWith(".$IME_EXTENSION") }.sortedBy { it.name }.forEach {
|
||||||
printdbg(this, "Registering High layer ${it.nameWithoutExtension.lowercase()}")
|
printdbg(this, "Registering High layer ${it.nameWithoutExtension.lowercase()}")
|
||||||
highLayers[it.nameWithoutExtension.lowercase()] = parseImeFile(it)
|
highLayers[it.nameWithoutExtension.lowercase()] = parseImeFile(it)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package net.torvald.terrarum.gamecontroller
|
package net.torvald.terrarum.gamecontroller
|
||||||
|
|
||||||
|
import net.torvald.terrarum.App.printdbg
|
||||||
|
import net.torvald.util.SortedArrayList
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileReader
|
import java.io.FileReader
|
||||||
|
|
||||||
@@ -13,11 +15,14 @@ class IMEProviderDelegate(val ime: IME) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class IMEDictionary(filename: String) {
|
class IMEDictionary(private val filename: String) {
|
||||||
|
|
||||||
private val candidates = HashMap<String, String>()
|
private val candidates = HashMap<String, String>(16384)
|
||||||
|
private val keys = SortedArrayList<String>(16384)
|
||||||
|
|
||||||
init {
|
private var dictLoaded = false
|
||||||
|
|
||||||
|
private fun loadDict() {
|
||||||
val reader = FileReader(File("assets/keylayout/", filename))
|
val reader = FileReader(File("assets/keylayout/", filename))
|
||||||
reader.forEachLine {
|
reader.forEachLine {
|
||||||
val (key, value) = it.split(',')
|
val (key, value) = it.split(',')
|
||||||
@@ -26,10 +31,38 @@ class IMEDictionary(filename: String) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
candidates[key] = value
|
candidates[key] = value
|
||||||
|
keys.add(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printdbg(this, "Dictionary loaded: $filename")
|
||||||
|
|
||||||
|
dictLoaded = true
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun get(key: String): String = candidates[key] ?: ""
|
init {
|
||||||
|
loadDict() // loading the dict doesn't take too long so no need to do it lazily
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun get(key: String): String {
|
||||||
|
//if (!dictLoaded) loadDict()
|
||||||
|
|
||||||
|
val out = StringBuilder()
|
||||||
|
var outsize = 0
|
||||||
|
var index = keys.searchForInterval(key) { it }.second
|
||||||
|
|
||||||
|
while (outsize < 10) {
|
||||||
|
val keysym = keys[index]
|
||||||
|
if (!keysym.startsWith(key)) break
|
||||||
|
|
||||||
|
val outstr = ",${candidates[keysym]}"
|
||||||
|
outsize += outstr.count { it == ',' }
|
||||||
|
out.append(outstr)
|
||||||
|
|
||||||
|
index += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (out.isNotEmpty()) out.substring(1) else ""
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ import com.badlogic.gdx.graphics.OrthographicCamera
|
|||||||
import com.badlogic.gdx.graphics.Pixmap
|
import com.badlogic.gdx.graphics.Pixmap
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||||
|
import com.jme3.math.FastMath
|
||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
import net.torvald.terrarum.gamecontroller.IME
|
import net.torvald.terrarum.gamecontroller.IME
|
||||||
import net.torvald.terrarum.gamecontroller.IngameController
|
import net.torvald.terrarum.gamecontroller.IngameController
|
||||||
@@ -121,6 +122,9 @@ class UIItemTextLineInput(
|
|||||||
private var imeOn = false
|
private var imeOn = false
|
||||||
private var candidates: List<CodepointSequence> = listOf()
|
private var candidates: List<CodepointSequence> = listOf()
|
||||||
|
|
||||||
|
private val candidatesBackCol = TEXTINPUT_COL_BACKGROUND.cpy().mul(1f,1f,1f,1.5f)
|
||||||
|
private val candidateNumberStrWidth = App.fontGame.getWidth("8. ")
|
||||||
|
|
||||||
private fun getIME(): TerrarumInputMethod? {
|
private fun getIME(): TerrarumInputMethod? {
|
||||||
if (!imeOn) return null
|
if (!imeOn) return null
|
||||||
|
|
||||||
@@ -228,7 +232,7 @@ class UIItemTextLineInput(
|
|||||||
// accept:
|
// accept:
|
||||||
// - literal "<"
|
// - literal "<"
|
||||||
// - keysymbol that does not start with "<" (not always has length of 1 because UTF-16)
|
// - keysymbol that does not start with "<" (not always has length of 1 because UTF-16)
|
||||||
else if (char != null && char[0].code >= 32 && (char == "<" || !char.startsWith("<"))) {
|
else if (char != null && char.length > 0 && char[0].code >= 32 && (char == "<" || !char.startsWith("<"))) {
|
||||||
val shiftin = keycodes.contains(Input.Keys.SHIFT_LEFT) || keycodes.contains(Input.Keys.SHIFT_RIGHT)
|
val shiftin = keycodes.contains(Input.Keys.SHIFT_LEFT) || keycodes.contains(Input.Keys.SHIFT_RIGHT)
|
||||||
val altgrin = keycodes.contains(Input.Keys.ALT_RIGHT)
|
val altgrin = keycodes.contains(Input.Keys.ALT_RIGHT)
|
||||||
|
|
||||||
@@ -343,8 +347,6 @@ class UIItemTextLineInput(
|
|||||||
return textbuf.toJavaString()
|
return textbuf.toJavaString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val candidateNumberStrWidth = App.fontGame.getWidth("8. ")
|
|
||||||
|
|
||||||
override fun render(batch: SpriteBatch, camera: Camera) {
|
override fun render(batch: SpriteBatch, camera: Camera) {
|
||||||
|
|
||||||
batch.end()
|
batch.end()
|
||||||
@@ -406,7 +408,7 @@ class UIItemTextLineInput(
|
|||||||
batch.draw(fbo.colorBufferTexture, posX + 2f, posY + 2f, fbo.width.toFloat(), fbo.height.toFloat())
|
batch.draw(fbo.colorBufferTexture, posX + 2f, posY + 2f, fbo.width.toFloat(), fbo.height.toFloat())
|
||||||
|
|
||||||
// draw text cursor
|
// draw text cursor
|
||||||
val cursorXOnScreen = posX - cursorDrawScroll + cursorDrawX + 3
|
val cursorXOnScreen = posX - cursorDrawScroll + cursorDrawX + 2
|
||||||
if (isActive && cursorOn) {
|
if (isActive && cursorOn) {
|
||||||
val baseCol = if (maxLen.exceeds(textbuf, listOf(32))) TEXTINPUT_COL_TEXT_NOMORE else TEXTINPUT_COL_TEXT
|
val baseCol = if (maxLen.exceeds(textbuf, listOf(32))) TEXTINPUT_COL_TEXT_NOMORE else TEXTINPUT_COL_TEXT
|
||||||
|
|
||||||
@@ -441,39 +443,56 @@ class UIItemTextLineInput(
|
|||||||
// draw candidates view
|
// draw candidates view
|
||||||
if (candidates.isNotEmpty()) {
|
if (candidates.isNotEmpty()) {
|
||||||
val textWidths = candidates.map { App.fontGame.getWidth(CodepointSequence(it)) }
|
val textWidths = candidates.map { App.fontGame.getWidth(CodepointSequence(it)) }
|
||||||
val candidateWinH = App.fontGame.lineHeight.toInt() * candidates.size
|
val candidatesMax = getIME()!!.maxCandidates()
|
||||||
|
val candidatesCount = minOf(candidatesMax, candidates.size)
|
||||||
|
val halfcount = FastMath.ceil(candidatesCount / 2f)
|
||||||
|
val candidateWinH = App.fontGame.lineHeight.toInt() * halfcount
|
||||||
|
val candidatePosX = cursorXOnScreen + 4
|
||||||
|
val candidatePosY = posY + 2
|
||||||
|
|
||||||
// candidate view text
|
// candidate view text
|
||||||
if (getIME()!!.maxCandidates() > 1) {
|
if (candidatesMax > 1) {
|
||||||
val candidateWinW = textWidths.maxOrNull()!!.coerceAtLeast(20) + candidateNumberStrWidth
|
val longestCandidateW = textWidths.maxOrNull()!! + candidateNumberStrWidth
|
||||||
|
val candidateWinW = if (candidatesCount == 1) longestCandidateW else 2*longestCandidateW + 3
|
||||||
|
|
||||||
// candidate view background
|
// candidate view background
|
||||||
batch.color = TEXTINPUT_COL_BACKGROUND
|
batch.color = candidatesBackCol
|
||||||
Toolkit.fillArea(batch, cursorXOnScreen + 2, posY + 27, candidateWinW + 4, candidateWinH)
|
Toolkit.fillArea(batch, candidatePosX, candidatePosY, candidateWinW + 4, candidateWinH)
|
||||||
// candidate view border
|
// candidate view border
|
||||||
batch.color = Toolkit.Theme.COL_ACTIVE
|
batch.color = Toolkit.Theme.COL_ACTIVE
|
||||||
Toolkit.drawBoxBorder(batch, cursorXOnScreen + 1, posY + 26, candidateWinW + 6, candidateWinH + 2)
|
Toolkit.drawBoxBorder(batch, candidatePosX - 1, candidatePosY - 1, candidateWinW + 6, candidateWinH + 2)
|
||||||
|
|
||||||
for (i in 0..minOf(9, candidates.lastIndex)) {
|
// candidate texts
|
||||||
|
for (i in 0 until candidatesCount) {
|
||||||
val candidateNum = listOf(i+48,46,32)
|
val candidateNum = listOf(i+48,46,32)
|
||||||
App.fontGame.draw(batch, CodepointSequence(candidateNum + candidates[i]), cursorXOnScreen + 4, posY + 27 + i * 20)
|
App.fontGame.draw(batch, CodepointSequence(candidateNum + candidates[i]),
|
||||||
|
candidatePosX + (i / halfcount) * (longestCandidateW + 3) + 2,
|
||||||
|
candidatePosY + (i % halfcount) * 20
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// candidate view splitter
|
||||||
|
if (candidatesCount > 1) {
|
||||||
|
batch.color = batch.color.cpy().mul(0.65f,0.65f,0.65f,1f)
|
||||||
|
Toolkit.fillArea(batch, candidatePosX + longestCandidateW + 2, candidatePosY, 1, candidateWinH)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val candidateWinW = textWidths.maxOrNull()!!.coerceAtLeast(20)
|
val candidateWinW = textWidths.maxOrNull()!!.coerceAtLeast(6)
|
||||||
|
|
||||||
// candidate view background
|
// candidate view background
|
||||||
batch.color = TEXTINPUT_COL_BACKGROUND
|
batch.color = candidatesBackCol
|
||||||
Toolkit.fillArea(batch, cursorXOnScreen + 2, posY + 27, candidateWinW, candidateWinH)
|
Toolkit.fillArea(batch, candidatePosX, candidatePosY, candidateWinW, candidateWinH)
|
||||||
// candidate view border
|
// candidate view border
|
||||||
batch.color = Toolkit.Theme.COL_ACTIVE
|
batch.color = Toolkit.Theme.COL_ACTIVE
|
||||||
Toolkit.drawBoxBorder(batch, cursorXOnScreen + 1, posY + 26, candidateWinW + 2, candidateWinH + 2)
|
Toolkit.drawBoxBorder(batch, candidatePosX - 1, candidatePosY - 1, candidateWinW + 2, candidateWinH + 2)
|
||||||
|
|
||||||
val previewTextWidth = textWidths[0]
|
val previewTextWidth = textWidths[0]
|
||||||
App.fontGame.draw(batch, candidates[0], cursorXOnScreen + 2 + (candidateWinW - previewTextWidth) / 2, posY + 27)
|
App.fontGame.draw(batch, candidates[0], candidatePosX + (candidateWinW - previewTextWidth) / 2, candidatePosY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
batch.color = Color.WHITE
|
||||||
super.render(batch, camera)
|
super.render(batch, camera)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,33 @@ class SortedArrayList<T: Comparable<T>>(initialSize: Int = 10) : MutableCollecti
|
|||||||
return null // key not found
|
return null // key not found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* e.g.
|
||||||
|
*
|
||||||
|
* 0 2 4 5 7 , find 3
|
||||||
|
*
|
||||||
|
* will return (1, 2), which corresponds value (2, 4) of which input value 3 is in between.
|
||||||
|
*/
|
||||||
|
fun <R: Comparable<R>> searchForInterval(searchQuery: R, searchHow: (T) -> R): Pair<Int,Int> {
|
||||||
|
var low: Int = 0
|
||||||
|
var high: Int = this.size - 1
|
||||||
|
|
||||||
|
while (low <= high) {
|
||||||
|
val mid = (low + high).ushr(1)
|
||||||
|
val midVal = searchHow(get(mid))
|
||||||
|
|
||||||
|
if (searchQuery < midVal)
|
||||||
|
high = mid - 1
|
||||||
|
else if (searchQuery > midVal)
|
||||||
|
low = mid + 1
|
||||||
|
else
|
||||||
|
return Pair(mid, mid)
|
||||||
|
}
|
||||||
|
|
||||||
|
val first = Math.max(high, 0)
|
||||||
|
val second = Math.min(low, this.size - 1)
|
||||||
|
return Pair(first, second)
|
||||||
|
}
|
||||||
/** Searches the element using given predicate instead of the element itself. Returns the element desired, null when there is no such element.
|
/** Searches the element using given predicate instead of the element itself. Returns the element desired, null when there is no such element.
|
||||||
* (e.g. search the Actor by its ID rather than the actor instance)
|
* (e.g. search the Actor by its ID rather than the actor instance)
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user