From 5db00e901949b983438185c4241ac6ae570d3adc Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Mon, 9 Oct 2023 18:03:12 +0000 Subject: [PATCH] repl tab completion; rgb text coloring --- scripts/base.js | 150 ++++++++++++++++++++++++++++++++--------- scripts/editor.js | 153 ++++++++++++++++++++++++++++++++++++------ scripts/engine.js | 19 ++++++ scripts/entity.js | 14 +++- scripts/gui.js | 39 +++++------ scripts/sound.js | 8 +-- scripts/textedit.js | 27 ++++++-- source/engine/ffi.c | 2 +- source/engine/font.c | 86 ++++++++++++++++++------ source/engine/font.h | 4 +- source/engine/input.c | 47 ++----------- source/engine/sound.c | 2 +- 12 files changed, 400 insertions(+), 151 deletions(-) diff --git a/scripts/base.js b/scripts/base.js index 88202c4..9e061e6 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -10,12 +10,38 @@ In addition to the removal of a bunch of stuff as seen here. Access prototypes through __proto__ instead of the long-winded Object.getProtoTypeOf. */ -var FNRM = function() { Log.error("removed"); }; -Object.getPrototypeOf = FNRM; -Object.setPrototypeOf = FNRM; -Reflect = {}; -Symbol = {}; -URIError = {}; + +Object.getPrototypeOf = undefined; +Object.setPrototypeOf = undefined; +Reflect = undefined; +Symbol = undefined; +URIError = undefined; +Proxy = undefined; +Map = undefined; +WeakMap = undefined; +Promise = undefined; +Set = undefined; +WeakSet = undefined; + +Object.methods = function(o) +{ + var m = []; + Object.keys(o).forEach(function(k) { + if (typeof o[k] === 'function') m.push(k); + }); + return m; +} + +Object.rkeys = function(o) +{ + var keys = []; + Object.keys(o).forEach(function(key) { + keys.push(key); + if (Object.isObject(o[key])) + keys.push(Object.rkeys(o[key])); + }); + return keys; +} Object.mixin = function(target, source) { @@ -356,49 +382,51 @@ Object.defineProperty(String.prototype, 'shift', { }); Object.defineProperty(String.prototype, 'strip_ext', { - value: function() { - var idx = this.lastIndexOf('.'); + value: function() { return this.tolast('.'); } +}); + +Object.defineProperty(String.prototype, 'ext', { + value: function() { return this.fromlast('.'); } +}); + +Object.defineProperty(String.prototype, 'set_ext', { + value: function(val) { return this.strip_ext() + val; } +}); + +Object.defineProperty(String.prototype, 'fromlast', { + value: function(val) { + var idx = this.lastIndexOf(val); + if (idx === -1) return ""; + return this.slice(idx+1); + } +}); + +Object.defineProperty(String.prototype, 'tolast', { + value: function(val) { + var idx = this.lastIndexOf(val); if (idx === -1) return this.slice(); return this.slice(0,idx); } }); -Object.defineProperty(String.prototype, 'ext', { - value: function() { - var idx = this.lastIndexOf('.'); - if (idx === -1) return undefined; - return this.slice(idx); - } -}); - -Object.defineProperty(String.prototype, 'set_ext', { +Object.defineProperty(String.prototype, 'tofirst', { value: function(val) { - var s = this.strip_ext(); - return s + val; + var idx = this.indexOf(val); + if (idx === -1) return this.slice(); + return this.slice(0,idx); } }); Object.defineProperty(String.prototype, 'name', { - value: function() { - var s = this.lastIndexOf('/'); - var e = this.lastIndexOf('.'); - if (e === -1) e = this.length; - return this.slice(s+1,e); - } + value: function() { return this.fromlast('/').tolast('.'); } }); Object.defineProperty(String.prototype, 'base', { - value: function() { - return this.slice(this.lastIndexOf('/')+1); - } + value: function() { return this.fromlast('/'); } }); Object.defineProperty(String.prototype, 'dir', { - value: function() { - var e = this.lastIndexOf('/'); - if (e === -1) return ""; - return this.slice(0, e); - } + value: function() { return this.tolast('/'); } }); Object.defineProperty(String.prototype, 'updir', { @@ -411,6 +439,25 @@ Object.defineProperty(String.prototype, 'updir', { } }); +Object.defineProperty(String.prototype, 'startswith', { + value: function(val) { + if (!val) return false; + return this.startsWith(val); + } +}); + +Object.defineProperty(String.prototype, 'endswith', { + value: function(val) { + if (!val) return false; + return this.endsWith(val); + } +}); + +Object.defineProperty(String.prototype, 'uc', { value: function() { return this.toUpperCase(); } }); + +Object.defineProperty(String.prototype, 'lc', {value:function() { return this.toLowerCase(); }}); + + /* ARRAY DEFS */ Object.defineProperty(Array.prototype, 'copy', { @@ -425,6 +472,36 @@ Object.defineProperty(Array.prototype, 'copy', { } }); +Object.defineProperty(Array.prototype, 'dofilter', { + value: function(fn) { + var j = 0; + this.forEach(function(val,i) { + if (fn(val)) { + if (i !== j) this[j] = val; + j++; + } + }, this); + this.length = j; + return this; + } +}); + + +function filterInPlace(a, condition, thisArg) { + let j = 0; + + a.forEach((e, i) => { + if (condition.call(thisArg, e, i, a)) { + if (i!==j) a[j] = e; + j++; + } + }); + + a.length = j; + return a; +} + + Object.defineProperty(Array.prototype, 'reversed', { value: function() { var c = this.slice(); @@ -693,6 +770,13 @@ Number.prec = function(num) return parseFloat(num.toFixed(3)); } +Number.hex = function(n) +{ + var s = Math.floor(n).toString(16); + if (s.length === 1) s = '0' + s; + return s.uc(); +} + Object.defineProperty(Object.prototype, 'lerp',{ value: function(to, t) { var self = this; diff --git a/scripts/editor.js b/scripts/editor.js index 62c9075..b24bab4 100644 --- a/scripts/editor.js +++ b/scripts/editor.js @@ -1278,7 +1278,7 @@ var inputpanel = { padding:[5,-15], gui() { - this.win = Mum.window({width:this.wh.x,height:this.wh.y, color:Color.black.alpha(0.1), anchor:this.anchor, padding:this.padding}); + this.win ??= Mum.window({width:this.wh.x,height:this.wh.y, color:Color.black.alpha(0.1), anchor:this.anchor, padding:this.padding}); var itms = this.guibody(); if (!Array.isArray(itms)) itms = [itms]; if (this.title) @@ -1356,29 +1356,44 @@ var inputpanel = { }; inputpanel.inputs = {}; + +inputpanel.inputs.post = function() +{ + this.keycb(); +} + inputpanel.inputs.char = function(c) { this.value = this.value.slice(0,this.caret) + c + this.value.slice(this.caret); this.caret++; - this.keycb(); } inputpanel.inputs['C-d'] = function() { this.value = this.value.slice(0,this.caret) + this.value.slice(this.caret+1); }; -inputpanel.inputs.tab = function() { this.value = tab_complete(this.value, this.assets); this.caret = this.value.length;} +inputpanel.inputs['C-d'].rep = true; +inputpanel.inputs.tab = function() { + this.value = tab_complete(this.value, this.assets); + this.caret = this.value.length; +} inputpanel.inputs.escape = function() { this.close(); } inputpanel.inputs['C-b'] = function() { if (this.caret === 0) return; this.caret--; }; +inputpanel.inputs['C-b'].rep = true; +inputpanel.inputs['C-u'] = function() +{ + this.value = this.value.slice(this.caret); + this.caret = 0; +} inputpanel.inputs['C-f'] = function() { if (this.caret === this.value.length) return; this.caret++; }; +inputpanel.inputs['C-f'].rep = true; inputpanel.inputs['C-a'] = function() { this.caret = 0; }; inputpanel.inputs['C-e'] = function() { this.caret = this.value.length; }; inputpanel.inputs.backspace = function() { if (this.caret === 0) return; this.value = this.value.slice(0,this.caret-1) + this.value.slice(this.caret); this.caret--; - this.keycb(); }; inputpanel.inputs.backspace.rep = true; inputpanel.inputs.enter = function() { this.submit(); } @@ -1387,7 +1402,6 @@ inputpanel.inputs['C-k'] = function() { this.value = this.value.slice(0,this.caret); }; - function proto_count_lvls(name) { if (!this.occs) this.occs = {}; @@ -1440,13 +1454,15 @@ var replpanel = Object.copy(inputpanel, { pos: [50,50], anchor: [0,0], padding: [0,0], + scrolloffset: [0,0], guibody() { + this.win.selectable = true; var log = cmd(84); - log = log.slice(-500); + log = log.slice(-5000); return [ - Mum.text({str:log, anchor:[0,0], offset:[0,-300]}), + Mum.text({str:log, anchor:[0,0], offset:[0,-300].sub(this.scrolloffset), selectable: true}), Mum.text({str:this.value,color:Color.green, offset:[0,-290], caret: this.caret}) ]; }, @@ -1470,9 +1486,72 @@ var replpanel = Object.copy(inputpanel, { var ret = function() {return eval(ecode);}.call(repl_obj); Log.say(ret); }, + + resetscroll() { + this.scrolloffset.y = 0; + }, }); replpanel.inputs = Object.create(inputpanel.inputs); +replpanel.inputs.tab = function() { + this.resetscroll(); + var obj = globalThis; + var keys = []; + var keyobj = this.value.tolast('.'); + var o = this.value.tolast('.'); + var stub = this.value.fromlast('.'); + var replobj = (editor.selectlist.length === 1) ? "editor.selectlist[0]" : "editor.edit_level"; + + if (this.value.startswith("this.")) + keyobj = keyobj.replace("this", replobj); + + if (!this.value.includes('.')) keys.push("this"); + + if (eval(`typeof ${keyobj.tofirst('.')}`) === 'object' && eval(`typeof ${keyobj.replace('.', '?.')}`) === 'object') { + Log.warn("set obj to " + keyobj); + obj = eval(keyobj); + } + else if (this.value.includes('.')){ + Log.say(`${this.value} is not an object.`); + return; + } + + for (var k in obj) + keys.push(k) + + var comp = ""; + if (stub) + comp = tab_complete(stub, keys); + else if (!this.value.includes('.')) + comp = tab_complete(o, keys); + else + comp = tab_complete("",keys); + + if (stub) + this.value = o + '.' + comp; + else if (this.value.endswith('.')) + this.value = o + '.' + comp; + else + this.value = comp; + + this.caret = this.value.length; + + keys = keys.sort(); + + keys = keys.map(function(x) { + if (typeof obj[x] === 'function') + return Esc.color(Color.Apple.orange) + x + Esc.reset; + if (Object.isObject(obj[x])) + return Esc.color(Color.Apple.purple) + x + Esc.reset; + if (Array.isArray(obj[x])) + return Esc.color(Color.Apple.green) + x + Esc.reset; + + return x; + }); + + if (keys.length > 1) + Log.say(keys.join(', ')); +}; replpanel.inputs['C-p'] = function() { if (this.prevmark >= this.prevthis.length) return; @@ -1493,6 +1572,40 @@ replpanel.inputs['C-n'] = function() this.inputs['C-e'].call(this); } +replpanel.inputs.mouse = {}; +replpanel.inputs.mouse.scroll = function(scroll) +{ + if (!this.win.selected) return; + + this.scrolloffset.y += scroll.y; + if (this.scrolloffset.y < 0) this.scrolloffset.y = 0; +} + +replpanel.inputs.up = function() +{ + this.scrolloffset.y += 40; +} +replpanel.inputs.up.rep = true; +replpanel.inputs.down = function() +{ + this.scrolloffset.y -= 40; + if (this.scrolloffset.y < 0) this.scrolloffset.y = 0; +} +replpanel.inputs.down.rep = true; + +replpanel.inputs.pgup = function() +{ + this.scrolloffset.y += 300; +} +replpanel.inputs.pgup.rep = true; + +replpanel.inputs.pgdown = function() +{ + this.scrolloffset.y -= 300; + if (this.scrolloffset.y < 0) this.scrolloffset.y = 0; +} +replpanel.inputs.pgdown.rep = true; + var objectexplorer = Object.copy(inputpanel, { title: "object explorer", obj: undefined, @@ -1778,29 +1891,27 @@ var assetexplorer = Object.copy(openlevelpanel, { }); function tab_complete(val, list) { - var check = list.filter(function(x) { return x.startsWith(val); }, this); - if (check.length === 1) { - list = check; - return check[0]; + if (!val) return val; + list.dofilter(function(x) { return x.startsWith(val); }); + Log.warn(list); + Log.warn(val); + if (list.length === 1) { + return list[0]; } var ret = undefined; var i = val.length; - while (!ret && !check.empty) { - - var char = check[0][i]; - if (!check.every(function(x) { return x[i] === char; })) - ret = check[0].slice(0, i); + while (!ret && !list.empty) { + var char = list[0][i]; + if (!list.every(function(x) { return x[i] === char; })) + ret = list[0].slice(0, i); else { i++; - check = check.filter(function(x) { return x.length-1 > i; }); + list.dofilter(function(x) { return x.length-1 > i; }); } } - if (!ret) return val; - - list = check; - return ret; + return ret ? ret : val; } var texgui = Object.copy(inputpanel, { diff --git a/scripts/engine.js b/scripts/engine.js index c082635..0ed2163 100644 --- a/scripts/engine.js +++ b/scripts/engine.js @@ -43,6 +43,25 @@ var Color = { purple: [162,93,227], }; +Color.tohtml = function(v) +{ + var html = v.map(function(n) { return Number.hex(n*255); }); + return "#" + html.join(''); +} + +Color.toesc = function(v) +{ + return Esc.color(v); +} + +var Esc = {}; +Esc.reset = "\x1b[0"; +Esc.color = function(v) { + var c = v.map(function(n) { return Math.floor(n*255); }); + var truecolor = "\x1b[38;2;" + c.join(';') + ';'; + return truecolor; +} + Color.Arkanoid = { orange: [255,143,0], teal: [0,255,255], diff --git a/scripts/entity.js b/scripts/entity.js index 7bad63d..b636563 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -183,6 +183,14 @@ var gameobject = { return bb.t-bb.b; }, + move(vec) { + this.pos = this.pos.add(vec); + }, + + rotate(amt) { + this.angle += amt; + }, + /* Make a unique object the same as its prototype */ revert() { Object.merge(this,this.__proto__); @@ -529,7 +537,11 @@ prototypes.from_file = function(file) var json = undefined; if (jsfile) script = IO.slurp(jsfile); - if (jsonfile) json = JSON.parse(IO.slurp(jsonfile)); + try { + if (jsonfile) json = JSON.parse(IO.slurp(jsonfile)); + } catch(e) { + Log.warn(e); + } if (!json && !script) { Log.warn(`Could not make ur from ${file}`); diff --git a/scripts/gui.js b/scripts/gui.js index 6f006da..32ff6aa 100644 --- a/scripts/gui.js +++ b/scripts/gui.js @@ -67,33 +67,34 @@ var GUI = { var gui_controls = {}; gui_controls.update = function() { }; -gui_controls.options = []; +gui_controls.set_mum = function(mum) +{ + mum.selected = true; + + if (this.selected && this.selected !== mum) + this.selected.selected = false; + + this.selected = mum; +} +gui_controls.check_bb = function(mum) +{ + if (pointinbb(mum.bb, Mouse.pos)) + gui_controls.set_mum(mum); +} gui_controls.inputs = {}; gui_controls.inputs.fallthru = false; gui_controls.inputs.mouse = {}; gui_controls.inputs.mouse.move = function(pos,dpos) { - var newsel = undefined; - this.options.forEach(function(x) { - if (pointinbb(x.bb,pos)) { - newsel = x; - return; - } - }); +} +gui_controls.inputs.mouse.scroll = function(scroll) +{ - if (this.selected && this.selected !== newsel) - this.selected.selected = false; - - this.selected = newsel; - if (this.selected) - this.selected.selected = true; } gui_controls.inputs.lm = function() { - if (this.selected) { - Log.warn(this.selected.str); + if (this.selected && this.selected.action) this.selected.action(this.selected); - } }; var Mum = { @@ -153,7 +154,7 @@ Mum.text = Mum.extend({ draw(cursor, cnt) { cnt ??= Mum; if (this.hide) return; - if (this.selectable) gui_controls.options.push_unique(this); + if (this.selectable) gui_controls.check_bb(this); this.caret ??= -1; /* if (!this.bb) @@ -209,7 +210,7 @@ Mum.window = Mum.extend({ GUI.flush(); GUI.scissor(p.x,p.y,this.wh.x,this.wh.y); this.max_width = this.width; - + if (this.selectable) gui_controls.check_bb(this); var pos = [this.bb.l, this.bb.t].add(this.padding); this.items.forEach(function(item) { if (item.hide) return; diff --git a/scripts/sound.js b/scripts/sound.js index a31fbda..d4d9f8b 100644 --- a/scripts/sound.js +++ b/scripts/sound.js @@ -19,11 +19,11 @@ var Music = { var Sound = { sounds: [], /* array of loaded sound files */ play(file) { -// var s = Object.create(Sound); -// s.path = file; -// s.play(); + if (!IO.exists(file)) { + Log.warn(`Cannot play sound ${file}: does not exist.`); + return; + } this.id = cmd(14,file); - //return s; }, music(midi, sf) { diff --git a/scripts/textedit.js b/scripts/textedit.js index 012796e..80bcad9 100644 --- a/scripts/textedit.js +++ b/scripts/textedit.js @@ -1,5 +1,6 @@ var texteditor = Object.copy(inputpanel, { title: "text editor", + wh: [700,500], _cursor:0, /* Text cursor: [char,line] */ get cursor() { return this._cursor; }, set cursor(x) { @@ -68,8 +69,11 @@ var texteditor = Object.copy(inputpanel, { return this.startbuffer !== this.value; }, + src: "NEW FILE", + guibody() { return [ + Mum.text({str:`EDITING ${this.src}`}), Mum.text({str:this.value, caret:this.cursor, offset:[0,-16]}), ]; }, @@ -170,6 +174,7 @@ var texteditor = Object.copy(inputpanel, { }); texteditor.inputs = {}; + texteditor.inputs.char = function(char) { this.insert_char(char); this.keycb(); @@ -192,11 +197,11 @@ texteditor.inputs.backspace.rep = true; texteditor.inputs['C-s'] = function() { - editor.edit_level.script = texteditor.value; - editor.save_current(); - texteditor.startbuffer = texteditor.value.slice(); + if (this.srctype === 'function') { + eval(`${this.src} = ${this.value}`); + } }; -texteditor.inputs['C-s'].doc = "Save script to file."; +texteditor.inputs['C-s'].doc = "Save edited text."; texteditor.inputs['C-u'] = function() { this.popstate(); }; texteditor.inputs['C-u'].doc = "Undo."; @@ -335,3 +340,17 @@ texteditor.inputs['M-n'] = function() { }; texteditor.inputs['M-n'].doc = "Go down to next line with text on it."; texteditor.inputs['M-n'].rep = true; + +texteditor.open_fn = function(fnstr) +{ + var fn = eval(fnstr); + if (!fn) { + Log.warn(`${fnstr} is not a function.`); + return; + } + this.src = fnstr; + this.srctype = "function"; + editor.openpanel(this); + this.value = fn; + this.cursor = 0; +} diff --git a/source/engine/ffi.c b/source/engine/ffi.c index 7fb4d6e..ec90d7b 100644 --- a/source/engine/ffi.c +++ b/source/engine/ffi.c @@ -277,7 +277,7 @@ JSValue vecarr2js(cpVect *points, int n) { } JSValue duk_ui_text(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { - const char *s = JS_ToCString(js, argv[0]); + const unsigned char *s = JS_ToCString(js, argv[0]); HMM_Vec2 pos = js2hmmv2(argv[1]); float size = js2number(argv[2]); diff --git a/source/engine/font.c b/source/engine/font.c index 5e2922c..b5c1a7c 100644 --- a/source/engine/font.c +++ b/source/engine/font.c @@ -23,7 +23,7 @@ struct sFont *font; -#define max_chars 4000 +#define max_chars 10000 static sg_shader fontshader; static sg_bindings bind_text; @@ -139,7 +139,7 @@ struct sFont *MakeFont(const char *fontfile, int height) { stbtt_GetFontVMetrics(&fontinfo, &newfont->ascent, &newfont->descent, &newfont->linegap); newfont->emscale = stbtt_ScaleForMappingEmToPixels(&fontinfo, 16); - newfont->linegap = (newfont->ascent - newfont->descent) * 1.5*newfont->emscale/2; + newfont->linegap = (newfont->ascent - newfont->descent) * newfont->emscale; newfont->texID = sg_make_image(&(sg_image_desc){ .type = SG_IMAGETYPE_2D, @@ -246,8 +246,37 @@ void text_settype(struct sFont *mfont) { font = mfont; } -struct boundingbox text_bb(const char *text, float scale, float lw, float tracking) +unsigned char *esc_color(unsigned char *c, struct rgba *color, struct rgba defc) { + struct rgba d; + if (!color) color = &d; + if (*c != '\e') c; + c++; + if (*c != '[') return c; + c++; + if (*c == '0') { + *color = defc; + c++; + return c; + } + else if (!strncmp(c, "38;2;", 5)) { + c += 5; + *color = (struct rgba){0,0,0,255}; + color->r = atoi(c); + c = strchr(c, ';')+1; + color->g = atoi(c); + c = strchr(c,';')+1; + color->b = atoi(c); + c = strchr(c,';')+1; + return c; + } + return c; +} + + +struct boundingbox text_bb(const unsigned char *text, float scale, float lw, float tracking) +{ + struct rgba dummy; HMM_Vec2 cursor = {0,0}; const unsigned char *c = text; const unsigned char *line, *wordstart, *drawstart; @@ -262,6 +291,9 @@ struct boundingbox text_bb(const char *text, float scale, float lw, float tracki cursor.X = 0; line++; } else { + if (*line == '\e') + line = esc_color(line, NULL, dummy); + wordstart = line; int wordWidth = 0; @@ -276,6 +308,9 @@ struct boundingbox text_bb(const char *text, float scale, float lw, float tracki } while (wordstart < line) { + if (*wordstart == '\e') + line = esc_color(wordstart, NULL, dummy); + cursor.X += font->Characters[*wordstart].Advance * tracking * scale; wordstart++; } @@ -291,38 +326,42 @@ void check_caret(int caret, int l, HMM_Vec2 pos, float scale, struct rgba color) draw_char_box(font->Characters[0], pos, scale, color); } + /* pos given in screen coordinates */ -int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking) { +int renderText(const unsigned char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking) { int len = strlen(text); HMM_Vec2 cursor = pos; - int l = 0; const unsigned char *line, *wordstart, *drawstart; line = drawstart = (unsigned char *)text; struct rgba usecolor = color; - check_caret(caret, l, cursor, scale, usecolor); + check_caret(caret, line-drawstart, cursor, scale, usecolor); - while (line[l] != '\0') { - if (isblank(line[l])) { - sdrawCharacter(font->Characters[line[l]], cursor, scale, usecolor); - cursor.X += font->Characters[line[l]].Advance * tracking * scale; - l++; - check_caret(caret, l, cursor, scale, usecolor); - } else if (isspace(line[l])) { - sdrawCharacter(font->Characters[line[l]], cursor, scale, usecolor); + while (*line != '\0') { + if (isblank(*line)) { + sdrawCharacter(font->Characters[*line], cursor, scale, usecolor); + cursor.X += font->Characters[*line].Advance * tracking * scale; + line++; + check_caret(caret, line-drawstart, cursor, scale, usecolor); + } else if (isspace(*line)) { + sdrawCharacter(font->Characters[*line], cursor, scale, usecolor); cursor.Y -= scale * font->linegap; cursor.X = pos.X; - l++; - check_caret(caret, l, cursor, scale, usecolor); + line++; + check_caret(caret, line-drawstart, cursor, scale, usecolor); } else { - wordstart = &line[l]; + if (*line == '\e') + line = esc_color(line, &usecolor, color); + + wordstart = line; int wordWidth = 0; - while (!isspace(line[l]) && line[l] != '\0') { - wordWidth += font->Characters[line[l]].Advance * tracking * scale; - l++; + while (!isspace(*line) && *line != '\0') { + + wordWidth += font->Characters[*line].Advance * tracking * scale; + line++; } if (lw > 0 && (cursor.X + wordWidth - pos.X) >= lw) { @@ -330,11 +369,14 @@ int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, f cursor.Y -= scale * font->linegap; } - while (wordstart < &line[l]) { + while (wordstart < line) { + if (*wordstart == '\e') + wordstart = esc_color(wordstart, &usecolor, color); + sdrawCharacter(font->Characters[*wordstart], cursor, scale, usecolor); cursor.X += font->Characters[*wordstart].Advance * tracking * scale; wordstart++; - check_caret(caret, wordstart-line, cursor, scale, usecolor); + check_caret(caret, wordstart-drawstart, cursor, scale, usecolor); } } } diff --git a/source/engine/font.h b/source/engine/font.h index c37fab0..72d0cfa 100644 --- a/source/engine/font.h +++ b/source/engine/font.h @@ -33,8 +33,8 @@ void font_init(); struct sFont *MakeFont(const char *fontfile, int height); void sdrawCharacter(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color); void text_settype(struct sFont *font); -struct boundingbox text_bb(const char *text, float scale, float lw, float tracking); -int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking); +struct boundingbox text_bb(const unsigned char *text, float scale, float lw, float tracking); +int renderText(const unsigned char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking); // void text_frame(); void text_flush(HMM_Mat4 *proj); diff --git a/source/engine/input.c b/source/engine/input.c index 35a8ecb..47d0f91 100644 --- a/source/engine/input.c +++ b/source/engine/input.c @@ -279,90 +279,52 @@ const char *keyname_extd(int key) { switch (key) { case SAPP_KEYCODE_ENTER: return "enter"; - break; - case SAPP_KEYCODE_ESCAPE: return "escape"; - break; - case SAPP_KEYCODE_DELETE: return "delete"; - break; - case SAPP_KEYCODE_INSERT: return "insert"; - break; - case SAPP_KEYCODE_TAB: return "tab"; - break; - case SAPP_KEYCODE_RIGHT: return "right"; - break; - case SAPP_KEYCODE_LEFT: return "left"; - break; - case SAPP_KEYCODE_UP: return "up"; - break; - case SAPP_KEYCODE_DOWN: return "down"; - break; - case SAPP_KEYCODE_LEFT_SHIFT: return "lshift"; - break; - case SAPP_KEYCODE_RIGHT_SHIFT: return "rshift"; - break; - case SAPP_KEYCODE_LEFT_CONTROL: return "lctrl"; - break; - case SAPP_KEYCODE_LEFT_ALT: return "lalt"; - break; - case SAPP_KEYCODE_RIGHT_CONTROL: return "rctrl"; - break; - case SAPP_KEYCODE_RIGHT_ALT: return "ralt"; - break; - case SAPP_KEYCODE_SPACE: return "space"; - break; - case SAPP_KEYCODE_KP_ADD: return "plus"; - break; - case SAPP_KEYCODE_KP_SUBTRACT: return "minus"; - break; case SAPP_KEYCODE_GRAVE_ACCENT: return "`"; - break; - case SAPP_KEYCODE_LEFT_BRACKET: return "lbracket"; - break; - case SAPP_KEYCODE_RIGHT_BRACKET: return "rbracket"; - break; - case SAPP_KEYCODE_BACKSPACE: return "backspace"; - break; + case SAPP_KEYCODE_PAGE_UP: + return "pgup"; + case SAPP_KEYCODE_PAGE_DOWN: + return "pgdown"; } if (key >= 32 && key <=90) { @@ -372,7 +334,6 @@ const char *keyname_extd(int key) { return keybuf; } - return "NULL"; } diff --git a/source/engine/sound.c b/source/engine/sound.c index c7acf90..976f736 100644 --- a/source/engine/sound.c +++ b/source/engine/sound.c @@ -153,7 +153,7 @@ struct wav *make_sound(const char *wav) { void *raw = slurp_file(wav, &rawlen); if (!raw) { YughError("Could not find file %s.", wav); - return; + return NULL; } if (!strcmp(ext, "wav"))