194 lines
4.2 KiB
JavaScript
194 lines
4.2 KiB
JavaScript
function UI(async, buttons, screen, session) {
|
|
var lineWidth = 36;
|
|
var textSpeeds = {
|
|
slow: 100,
|
|
medium: 50,
|
|
fast: 20
|
|
};
|
|
var textDelay = textSpeeds[session.getOptions().textSpeed];
|
|
|
|
return {
|
|
animation: animation,
|
|
ask: ask,
|
|
cinematic: cinematic,
|
|
frame: frame,
|
|
menu: menu,
|
|
text: text
|
|
};
|
|
|
|
function animation(frames) {
|
|
var frameCounter = 0;
|
|
var scheduled;
|
|
var step = function() {
|
|
if(frameCounter < frames.length) {
|
|
scheduled = null;
|
|
frames[frameCounter].action();
|
|
if(frames[frameCounter].delay != undefined) {
|
|
scheduled = setTimeout(step, frames[frameCounter].delay);
|
|
}
|
|
frameCounter++
|
|
}
|
|
};
|
|
return {
|
|
run: step,
|
|
pause: function() { if(scheduled != undefined) { clearTimeout(scheduled); } }
|
|
};
|
|
}
|
|
|
|
function cinematic(frames, controls) {
|
|
var remote = animation(frames);
|
|
var mapping = {};
|
|
var escaper = function(f) {
|
|
return function() {
|
|
buttons.pop();
|
|
remote.pause();
|
|
f();
|
|
};
|
|
}
|
|
for(var key in controls) {
|
|
mapping[key] = escaper(controls[key]);
|
|
}
|
|
return function(f) {
|
|
buttons.push(mapping);
|
|
remote.run();
|
|
f();
|
|
};
|
|
}
|
|
|
|
function close(elem) {
|
|
buttons.pop();
|
|
screen.clear(elem);
|
|
}
|
|
|
|
function frame(id) {
|
|
screen.clear();
|
|
screen.frame(id);
|
|
}
|
|
|
|
function menu(config) {
|
|
var cursor = 0;
|
|
var m = screen.menu(config.name + 'Menu', config.entries);
|
|
var sync = function() { screen.select(cursor); };
|
|
var mapping = {
|
|
Up: function() {
|
|
cursor = (config.entries.length + cursor - 1) % config.entries.length;
|
|
sync();
|
|
},
|
|
Down: function() {
|
|
cursor = (cursor + 1) % config.entries.length;
|
|
sync();
|
|
},
|
|
A: function() {
|
|
var entry = config.entries[cursor];
|
|
if(entry.action != undefined) {
|
|
entry.action(m);
|
|
} else if(entry.quit != undefined) {
|
|
close(m);
|
|
entry.quit();
|
|
}
|
|
}
|
|
};
|
|
if(config.cancel != undefined) {
|
|
mapping['B'] = function() { close(m); config.cancel(); }
|
|
}
|
|
buttons.push(mapping);
|
|
}
|
|
|
|
function ask(config) {
|
|
var menuConfig = {entries: [], name: config.name};
|
|
var apply = function(f, val) { return function() { return f(val); }; };
|
|
return function(f) {
|
|
for(var i = 0; i < config.entries.length; i++) {
|
|
var entry;
|
|
if(config.entries[i].label != undefined) {
|
|
entry = {label: config.entries[i].label, quit: apply(f, config.entries[i].value)};
|
|
} else {
|
|
entry = {label: '___', action: promptValue(config.entries[i].size, f)};
|
|
}
|
|
menuConfig.entries.push(entry);
|
|
}
|
|
menu(menuConfig);
|
|
};
|
|
}
|
|
|
|
function promptValue(size, f) {
|
|
return function(m) {
|
|
var input = screen.input(size);
|
|
input.focus();
|
|
buttons.push({});
|
|
input.addEventListener('keydown', function(event) {
|
|
switch(event.key) {
|
|
case 'Escape': close(input); break;
|
|
case 'Enter':
|
|
var value = input.value;
|
|
close(input);
|
|
close(m);
|
|
return f(value);
|
|
}
|
|
});
|
|
};
|
|
}
|
|
|
|
function textScreen(message) {
|
|
var characters = message.split('');
|
|
var frames = [];
|
|
var ready = false;
|
|
var append = function(c) { return function() { screen.appendText(c); }; };
|
|
for(var i = 0; i < characters.length; i++) {
|
|
frames.push({action: append(characters[i]), delay: textDelay});
|
|
}
|
|
frames.push({action: function() { ready = true; screen.markAsRead(); }, delay: null});
|
|
var remote = animation(frames);
|
|
return function(f) {
|
|
buttons.push({
|
|
'A': function() {
|
|
if(ready) {
|
|
f();
|
|
} else {
|
|
remote.pause();
|
|
screen.text(message);
|
|
ready = true;
|
|
}
|
|
}
|
|
});
|
|
screen.text('');
|
|
remote.run();
|
|
};
|
|
}
|
|
|
|
function text(message) {
|
|
var words = message.split(' ');
|
|
var i = 0;
|
|
var line = '';
|
|
var screen = null;
|
|
var screens = [];
|
|
var width = 0;
|
|
while (i < words.length) {
|
|
if(width == 0) {
|
|
line = words[i];
|
|
width += line.length;
|
|
i++;
|
|
} else {
|
|
if(width + words[i].length + 1 <= lineWidth) {
|
|
line += ' ' + words[i];
|
|
width += 1 + words[i].length;
|
|
i++;
|
|
} else {
|
|
if(screen === null) {
|
|
screen = line;
|
|
} else {
|
|
screens.push(screen + ' ' + line);
|
|
screen = null;
|
|
}
|
|
line = '';
|
|
width = 0;
|
|
}
|
|
}
|
|
}
|
|
screens.push(screen === null ? line : screen + ' ' + line);
|
|
return async.sequence.apply(null,
|
|
screens.map(function(s) { return textScreen(s); })
|
|
);
|
|
}
|
|
}
|