font caret underlining; repl line editing
This commit is contained in:
parent
5578b0f7e4
commit
8c69dfd71f
|
@ -17,7 +17,7 @@ Reflect = {};
|
|||
Symbol = {};
|
||||
URIError = {};
|
||||
|
||||
Object.complete_assign = function(target, source)
|
||||
Object.mixin = function(target, source)
|
||||
{
|
||||
if (typeof source === 'undefined') return target;
|
||||
|
||||
|
@ -150,7 +150,7 @@ Object.copy = function(proto, ...objs)
|
|||
{
|
||||
var c = Object.create(proto);
|
||||
for (var obj of objs)
|
||||
Object.complete_assign(c, obj);
|
||||
Object.mixin(c, obj);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -160,15 +160,17 @@ Object.defHidden = function(obj, prop)
|
|||
Object.defineProperty(obj, prop, {enumerable:false, writable:true});
|
||||
}
|
||||
|
||||
Object.hide = function(obj,prop)
|
||||
Object.hide = function(obj,...props)
|
||||
{
|
||||
var p = Object.getOwnPropertyDescriptor(obj,prop);
|
||||
if (!p) {
|
||||
Log.warn(`No property of name ${prop}.`);
|
||||
return;
|
||||
for (var prop of props) {
|
||||
var p = Object.getOwnPropertyDescriptor(obj,prop);
|
||||
if (!p) {
|
||||
Log.warn(`No property of name ${prop}.`);
|
||||
return;
|
||||
}
|
||||
p.enumerable = false;
|
||||
Object.defineProperty(obj, prop, p);
|
||||
}
|
||||
p.enumerable = false;
|
||||
Object.defineProperty(obj, prop, p);
|
||||
}
|
||||
|
||||
Object.defineProperty(Object.prototype, 'obscure', {
|
||||
|
|
|
@ -30,17 +30,17 @@ component.sprite = Object.copy(component, {
|
|||
layer:0,
|
||||
enabled:true,
|
||||
path: "",
|
||||
rect: {s0:0, s1: 1, t0: 0, t1: 1},
|
||||
toString() { return "sprite"; },
|
||||
make(go) {
|
||||
var nsprite = Object.create(this);
|
||||
nsprite.gameobject = go;
|
||||
Object.assign(nsprite, make_sprite(go.body));
|
||||
Object.complete_assign(nsprite, component.sprite.impl);
|
||||
Object.mixin(nsprite, component.sprite.impl);
|
||||
Object.hide(nsprite, 'gameobject', 'id');
|
||||
for (var p in component.sprite.impl)
|
||||
if (typeof this[p] !== 'undefined') {
|
||||
Log.warn(`setting ${p}`);
|
||||
if (typeof this[p] !== 'undefined')
|
||||
nsprite[p] = this[p];
|
||||
}
|
||||
return nsprite;
|
||||
},
|
||||
});
|
||||
|
@ -55,7 +55,6 @@ component.sprite.impl = {
|
|||
hide() { this.enabled = false; },
|
||||
show() { this.enabled = true; },
|
||||
asset(str) { this.path = str; },
|
||||
rect: {s0:0, s1: 1, t0: 0, t1: 1},
|
||||
get enabled() { return cmd(114,this.id); },
|
||||
set enabled(x) { cmd(20,this.id,x); },
|
||||
set color(x) { cmd(96,this.id,x); },
|
||||
|
@ -705,8 +704,8 @@ component.circle2d = Object.copy(collider2d, {
|
|||
var circle = Object.create(this);
|
||||
circle.gameobject = go;
|
||||
Object.assign(circle, make_circle2d(go.body));
|
||||
Object.complete_assign(circle,this.impl);
|
||||
|
||||
Object.mixin(circle,this.impl);
|
||||
Object.hide(circle, 'gameobject', 'id', 'shape', 'scale');
|
||||
return circle;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -88,6 +88,45 @@ function positive_diff(from, to)
|
|||
var diff = {};
|
||||
}
|
||||
|
||||
function vdiff(from,to)
|
||||
{
|
||||
if (typeof from === 'number') {
|
||||
var a = Number.prec(from);
|
||||
return a === to ? undefined : a;
|
||||
}
|
||||
|
||||
if (typeof from === 'object') {
|
||||
var ret = {};
|
||||
Object.keys(from).forEach(function(k) {
|
||||
var diff = vdiff(from[k], to[k]);
|
||||
if (diff) ret[k] = diff;
|
||||
});
|
||||
return ret.empty ? undefined : ret;
|
||||
}
|
||||
}
|
||||
|
||||
function gdiff(from, to) {
|
||||
var obj = {};
|
||||
|
||||
Object.entries(from).forEach(function([k,v]) {
|
||||
if (typeof v === 'function') return;
|
||||
if (!Object.isAccessor(from, k)) {
|
||||
obj[k] = v;
|
||||
return;
|
||||
}
|
||||
|
||||
var diff = vdiff(v, to[k]);
|
||||
if (diff) {
|
||||
if (Array.isArray(v))
|
||||
obj[k] = Object.values(diff);
|
||||
else
|
||||
obj[k] = diff;
|
||||
}
|
||||
});
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
function diff(from, to) {
|
||||
var obj = {};
|
||||
|
||||
|
@ -102,10 +141,5 @@ function diff(from, to) {
|
|||
}
|
||||
}
|
||||
|
||||
for (var e in from) {
|
||||
if (!to.hasOwnProperty(e))
|
||||
obj[e] = "DELETE";
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
|
|
@ -402,7 +402,7 @@ var editor = {
|
|||
lvlchain.forEach(function(x,i) {
|
||||
lvlcolor = colormap.sample(lvlcolorsample);
|
||||
var lvlstr = x.toString();
|
||||
if (x.dirty)
|
||||
if (x._ed.dirty)
|
||||
lvlstr += "*";
|
||||
if (i === lvlchain.length-1) lvlstr += "[this]";
|
||||
GUI.text(lvlstr, [0, ypos], 1, lvlcolor);
|
||||
|
@ -421,12 +421,12 @@ var editor = {
|
|||
|
||||
this.selectlist.forEach(function(x) {
|
||||
var sname = x.__proto__.toString();
|
||||
if (!x.level_obj().empty)
|
||||
x.dirty = true;
|
||||
if (!x.json_obj().empty)
|
||||
x._ed.dirty = true;
|
||||
else
|
||||
x.dirty = false;
|
||||
x._ed.dirty = false;
|
||||
|
||||
if (x.dirty) sname += "*";
|
||||
if (x._ed.dirty) sname += "*";
|
||||
|
||||
GUI.text(sname, world2screen(x.worldpos()).add([0, 16]), 1, lvlcolor);
|
||||
GUI.text(x.worldpos().map(function(x) { return Math.round(x); }), world2screen(x.worldpos()), 1, Color.white);
|
||||
|
@ -788,7 +788,7 @@ editor.inputs['C-s'] = function() {
|
|||
return;
|
||||
};
|
||||
|
||||
if (editor.selectlist.length !== 1 || !editor.selectlist[0].dirty) return;
|
||||
if (editor.selectlist.length !== 1 || !editor.selectlist[0]._ed.dirty) return;
|
||||
Object.merge(editor.selectlist[0].ur, editor.selectlist[0].level_obj());
|
||||
var path = editor.selectlist[0].ur.toString();
|
||||
path = path.replaceAll('.','/');
|
||||
|
@ -818,7 +818,7 @@ editor.inputs['M-t'] = function() { editor.edit_level.objects.forEach(function(x
|
|||
editor.inputs['M-t'].doc = "Unlock all objects in current level.";
|
||||
|
||||
editor.inputs['C-n'] = function() {
|
||||
if (editor.edit_level.dirty) {
|
||||
if (editor.edit_level._ed.dirty) {
|
||||
Log.info("Level has changed; save before starting a new one.");
|
||||
editor.openpanel(gen_notify("Level is changed. Are you sure you want to close it?", _ => editor.clear_level()));
|
||||
return;
|
||||
|
@ -835,14 +835,14 @@ editor.inputs['C-o'].doc = "Open a level.";
|
|||
|
||||
editor.inputs['C-M-o'] = function() {
|
||||
if (editor.selectlist.length === 1 && editor.selectlist[0].file) {
|
||||
if (editor.edit_level.dirty) return;
|
||||
if (editor.edit_level._ed.dirty) return;
|
||||
editor.load(editor.selectlist[0].file);
|
||||
}
|
||||
};
|
||||
editor.inputs['C-M-o'].doc = "Revert opened level back to its disk form.";
|
||||
|
||||
editor.inputs['C-S-o'] = function() {
|
||||
if (!editor.edit_level.dirty)
|
||||
if (!editor.edit_level._ed.dirty)
|
||||
editor.load_prev();
|
||||
};
|
||||
editor.inputs['C-S-o'].doc = "Open previous level.";
|
||||
|
@ -1331,13 +1331,19 @@ inputpanel.inputs = {};
|
|||
inputpanel.inputs.char = function(c) {
|
||||
this.value = this.value.slice(0,this.caret) + c + this.value.slice(this.caret);
|
||||
this.caret++;
|
||||
Log.warn(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); }
|
||||
inputpanel.inputs.escape = function() { this.close(); }
|
||||
inputpanel.inputs['C-b'] = function() {
|
||||
if (this.caret === 0) return;
|
||||
this.caret--;
|
||||
};
|
||||
inputpanel.inputs['C-a'] = function() { this.caret = 0; };
|
||||
inputpanel.inputs['C-f'] = 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();
|
||||
|
@ -1413,6 +1419,7 @@ var replpanel = Object.copy(inputpanel, {
|
|||
action() {
|
||||
if (!this.value) return;
|
||||
this.prevthis.unshift(this.value);
|
||||
this.prevmark = -1;
|
||||
var ecode = "";
|
||||
var repl_obj = (editor.selectlist.length === 1) ? editor.selectlist[0] : editor.edit_level;
|
||||
ecode += `var $ = repl_obj.objects;`;
|
||||
|
@ -1435,6 +1442,7 @@ replpanel.inputs['C-p'] = function()
|
|||
if (this.prevmark >= this.prevthis.length) return;
|
||||
this.prevmark++;
|
||||
this.value = this.prevthis[this.prevmark];
|
||||
this.inputs['C-f'].call(this);
|
||||
}
|
||||
|
||||
replpanel.inputs['C-n'] = function()
|
||||
|
@ -1445,6 +1453,8 @@ replpanel.inputs['C-n'] = function()
|
|||
this.value = "";
|
||||
} else
|
||||
this.value = this.prevthis[this.prevmark];
|
||||
|
||||
this.inputs['C-f'].call(this);
|
||||
}
|
||||
|
||||
var objectexplorer = Object.copy(inputpanel, {
|
||||
|
@ -1670,10 +1680,7 @@ var quitpanel = Object.copy(inputpanel, {
|
|||
},
|
||||
|
||||
guibody () {
|
||||
Nuke.label("Really quit?");
|
||||
Nuke.newline(2);
|
||||
if (Nuke.button("yes"))
|
||||
this.submit();
|
||||
return Mum.text({str: "Really quit?"});
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -1848,6 +1855,3 @@ Game.stop();
|
|||
Game.editor_mode(true);
|
||||
|
||||
load("editorconfig.js");
|
||||
|
||||
Log.warn(ur.ball);
|
||||
Log.warn(ur['ball.big']);
|
||||
|
|
|
@ -204,6 +204,7 @@ var gameobject = {
|
|||
velocity:[0,0],
|
||||
angularvelocity:0,
|
||||
layer:0,
|
||||
|
||||
save:true,
|
||||
selectable:true,
|
||||
ed_locked:false,
|
||||
|
@ -290,11 +291,19 @@ var gameobject = {
|
|||
if (ret.empty) return undefined;
|
||||
return ret;
|
||||
},
|
||||
|
||||
|
||||
json_obj() {
|
||||
var ur = gameobject.diff(this,this.__proto__);
|
||||
|
||||
return ur ? ur : {};
|
||||
var d = gdiff(this,this.__proto__);
|
||||
delete d.pos;
|
||||
delete d.angle;
|
||||
delete d.velocity;
|
||||
delete d.angularvelocity;
|
||||
d.components = [];
|
||||
this.components.forEach(function(x) {
|
||||
var c = gdiff(x, x.__proto__);
|
||||
if (c) d.components.push(c);
|
||||
});
|
||||
return d;
|
||||
},
|
||||
|
||||
transform_obj() {
|
||||
|
@ -398,17 +407,20 @@ var gameobject = {
|
|||
right() { return [1,0].rotate(Math.deg2rad(this.angle));},
|
||||
left() { return [-1,0].rotate(Math.deg2rad(this.angle));},
|
||||
instances: [],
|
||||
|
||||
make(level) {
|
||||
level ??= Primum;
|
||||
var obj = Object.create(this);
|
||||
this.instances.push(obj);
|
||||
obj.body = make_gameobject();
|
||||
Object.hide(obj, 'body');
|
||||
obj.components = {};
|
||||
obj.objects = {};
|
||||
Object.complete_assign(obj, gameobject.impl);
|
||||
Object.mixin(obj, gameobject.impl);
|
||||
Object.hide(obj, 'components');
|
||||
Object.hide(obj, 'objects');
|
||||
obj.toJSON = gameobject.level_json;
|
||||
obj._ed = {};
|
||||
Object.hide(obj, '_ed');
|
||||
|
||||
Game.register_obj(obj);
|
||||
|
||||
|
@ -416,6 +428,8 @@ var gameobject = {
|
|||
|
||||
obj.reparent(level);
|
||||
|
||||
Object.hide(obj, 'level')
|
||||
|
||||
for (var prop in this) {
|
||||
var p = this[prop];
|
||||
if (typeof p !== 'object') continue;
|
||||
|
@ -423,10 +437,12 @@ var gameobject = {
|
|||
if ('ur' in p) {
|
||||
obj[prop] = obj.spawn(prototypes.get_ur(p.ur));
|
||||
obj.rename_obj(obj[prop].toString(), prop);
|
||||
Object.hide(obj, prop);
|
||||
} else if ('comp' in p) {
|
||||
Log.warn(p);
|
||||
obj[prop] = Object.assign(component[p.comp].make(obj), p);
|
||||
obj.components[prop] = obj[prop];
|
||||
Object.hide(obj,prop);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -117,8 +117,7 @@ Mum.text = Mum.extend({
|
|||
this.calc_bb(cursor);
|
||||
var aa = [0,1].sub(this.anchor);
|
||||
var pos = cursor.add(this.wh.scale(aa)).add(this.offset);
|
||||
if (this.caret > -1) Log.warn(`Drawing box at pos ${this.caret} over letter ${this.str[this.caret-1]}`);
|
||||
ui_text(this.str, pos, this.font_size, this.color, -1, this.width, this.caret);
|
||||
ui_text(this.str, pos, this.font_size, this.color, this.width, this.caret);
|
||||
},
|
||||
|
||||
update_bb(cursor) {
|
||||
|
|
|
@ -1622,7 +1622,7 @@ void ffi_load() {
|
|||
DUK_FUNC(register, 3)
|
||||
DUK_FUNC(register_collide, 6)
|
||||
|
||||
DUK_FUNC(ui_text, 6)
|
||||
DUK_FUNC(ui_text, 8)
|
||||
DUK_FUNC(gui_img, 10)
|
||||
|
||||
DUK_FUNC(inflate_cpv, 3)
|
||||
|
|
|
@ -181,6 +181,9 @@ static int curchar = 0;
|
|||
|
||||
void draw_char_box(struct Character c, HMM_Vec2 cursor, float scale, struct rgba color)
|
||||
{
|
||||
cursor.Y -= 2;
|
||||
sdrawCharacter(font->Characters['_'], cursor, scale, color);
|
||||
return;
|
||||
cpVect wh;
|
||||
|
||||
wh.x = 8 * scale;
|
||||
|
@ -281,37 +284,44 @@ struct boundingbox text_bb(const char *text, float scale, float lw, float tracki
|
|||
return cwh2bb((HMM_Vec2){0,0}, (HMM_Vec2){cursor.X,font->linegap-cursor.Y});
|
||||
}
|
||||
|
||||
void check_caret(int caret, int l, HMM_Vec2 pos, float scale, struct rgba color)
|
||||
{
|
||||
if (caret == l)
|
||||
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 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);
|
||||
|
||||
while (*line != '\0') {
|
||||
if (caret >= 0 && caret == curchar)
|
||||
draw_char_box(font->Characters[69], cursor, scale, color);
|
||||
|
||||
if (isblank(*line)) {
|
||||
sdrawCharacter(font->Characters[*line], cursor, scale, usecolor);
|
||||
cursor.X += font->Characters[*line].Advance * tracking * scale;
|
||||
line++;
|
||||
} else if (isspace(*line)) {
|
||||
sdrawCharacter(font->Characters[*line], 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);
|
||||
cursor.Y -= scale * font->linegap;
|
||||
cursor.X = pos.X;
|
||||
line++;
|
||||
l++;
|
||||
check_caret(caret, l, cursor, scale, usecolor);
|
||||
} else {
|
||||
wordstart = line;
|
||||
wordstart = &line[l];
|
||||
int wordWidth = 0;
|
||||
|
||||
while (!isspace(*line) && *line != '\0') {
|
||||
wordWidth += font->Characters[*line].Advance * tracking * scale;
|
||||
line++;
|
||||
while (!isspace(line[l]) && line[l] != '\0') {
|
||||
wordWidth += font->Characters[line[l]].Advance * tracking * scale;
|
||||
l++;
|
||||
}
|
||||
|
||||
if (lw > 0 && (cursor.X + wordWidth - pos.X) >= lw) {
|
||||
|
@ -319,15 +329,14 @@ int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, f
|
|||
cursor.Y -= scale * font->linegap;
|
||||
}
|
||||
|
||||
while (wordstart < line) {
|
||||
while (wordstart < &line[l]) {
|
||||
sdrawCharacter(font->Characters[*wordstart], cursor, scale, usecolor);
|
||||
cursor.X += font->Characters[*wordstart].Advance * tracking * scale;
|
||||
wordstart++;
|
||||
check_caret(caret, wordstart-line, cursor, scale, usecolor);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (caret > curchar)
|
||||
// draw_char_box(font->Characters[69], cursor, scale, color);
|
||||
|
||||
return cursor.Y - pos.Y;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue