Added scribble app, icon and params.
parent
100384f2e8
commit
d3d6a845ff
|
|
@ -0,0 +1 @@
|
|||
0.01: Initial release
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# App Name
|
||||
|
||||
Describe the app...
|
||||
|
||||
Add screen shots (if possible) to the app folder and link then into this file with 
|
||||
|
||||
## Usage
|
||||
|
||||
Describe how to use it
|
||||
|
||||
## Features
|
||||
|
||||
Name the function
|
||||
|
||||
## Controls
|
||||
|
||||
Name the buttons and what they are used for
|
||||
|
||||
## Requests
|
||||
|
||||
Name who should be contacted for support/update requests
|
||||
|
||||
## Creator
|
||||
|
||||
Your name
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
{ "id": "scribble",
|
||||
"name": "Scribble",
|
||||
"shortName":"Scribble",
|
||||
"version":"0.01",
|
||||
"description": "A keyboard on your wrist!",
|
||||
"icon": "app.png",
|
||||
"tags": "keyboard, text, scribble",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"scribble.app.js","url":"app.js"},
|
||||
{"name":"scribble.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
var img = require("heatshrink").decompress(atob("mEwwMB/4A2/IFE+IFE+YFE84FE44FE54SEz/jAocfDAk/54EC/1/x4FC/l/z4FDCQJGD/wFD+IYBIwYSBIwf4IwhfEIwuPIwkPIwMAj//g/P/gFCkOP/AEB/8wj5+Dn0/Aoc8n/4JAU4v/8gYFBaYWAJ4MHAoPwEgMPOgUfLogJCBYQFE+AFD8BHB/EAAAV/AoYyCB4IKBc6QA=="))
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -0,0 +1,469 @@
|
|||
const black = "#000000";
|
||||
const white = "#ffffff";
|
||||
const gray1 = "#444444";
|
||||
const gray2 = "#888888";
|
||||
const gray3 = "#bbbbbb";
|
||||
|
||||
const red = "#FF0000";
|
||||
const green = "#00FF00";
|
||||
const blue = "#0000FF";
|
||||
|
||||
const transp = -1;
|
||||
const abc = "abcdefghijklmnopqrstuvwxyz1234567890";
|
||||
// const abc_up = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
||||
const uppercase = 1;
|
||||
const last_layer = false; // set to true at the last layer of the tree
|
||||
let chunk_size = 6;
|
||||
|
||||
const font_height = 2;
|
||||
const global_font = "Dennis8";
|
||||
require("FontDennis8").add(Graphics);
|
||||
|
||||
const editable_buf = "hello";
|
||||
|
||||
const left = 4;
|
||||
const _screen_mid = g.getWidth() / 2;
|
||||
const right = 176 - 4;
|
||||
|
||||
const box_size = {
|
||||
w: _screen_mid - 6,
|
||||
h: 45,
|
||||
};
|
||||
|
||||
const spacing = 4;
|
||||
const border = 4;
|
||||
const top_start = 25;
|
||||
|
||||
const pos_y = [
|
||||
top_start,
|
||||
top_start + (box_size.h + spacing),
|
||||
top_start + (box_size.h + spacing) * 2,
|
||||
];
|
||||
|
||||
// list of points to render
|
||||
const points = {
|
||||
"3x2": [{ x: left, y: pos_y[0] },
|
||||
{ x: left, y: pos_y[1] },
|
||||
{ x: left, y: pos_y[2] },
|
||||
{ x: _screen_mid + 2, y: pos_y[0] },
|
||||
{ x: _screen_mid + 2, y: pos_y[1] },
|
||||
{ x: _screen_mid + 2, y: pos_y[2] },
|
||||
]
|
||||
};
|
||||
|
||||
g.theme = {
|
||||
fg: white,
|
||||
bg: black,
|
||||
fg2: white,
|
||||
bg2: black,
|
||||
fgH: black,
|
||||
bgH: red,
|
||||
dark: false,
|
||||
};
|
||||
|
||||
const maxX = g.getWidth();
|
||||
const maxY = g.getHeight();
|
||||
const fontSize = g.getWidth() > 200 ? 2 : 1;
|
||||
const rowN = 7;
|
||||
const colN = 7;
|
||||
const headerH = maxY / 7;
|
||||
const rowH = (maxY - headerH) / rowN;
|
||||
const colW = maxX / colN;
|
||||
|
||||
function getRndInteger(min, max) {
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
}
|
||||
|
||||
class Window {
|
||||
constructor(label, bgCol) {
|
||||
this.label = "win_"
|
||||
this.label += (typeof label !== "undefined") ? label : "Unset";
|
||||
console.log(`Constructing Window ${this.label}, args: ${arguments}`)
|
||||
|
||||
this.bgCol = bgCol;
|
||||
this.layers = [];
|
||||
}
|
||||
|
||||
push(layer) {
|
||||
layer.label=`${this.layers.length}_${layer.label}`;
|
||||
this.layers.push(layer);
|
||||
}
|
||||
pop() {
|
||||
this.layers.pop();
|
||||
}
|
||||
|
||||
top_layer() {
|
||||
return this.layers[this.layers.length - 1];
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
if (this.bgCol !== transp) {
|
||||
console.log(`${this.label}: filling bg in ${this.bgCol}`);
|
||||
g.setColor(this.bgCol);
|
||||
g.fillRect(0, 0, g.getWidth(), g.getHeight());
|
||||
}
|
||||
|
||||
|
||||
let i = 0;
|
||||
this.layers.forEach((lyr) => {
|
||||
// console.log(`Rendering Layer ${i} ${lyr.label}`)
|
||||
i++;
|
||||
lyr.render();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class Layer {
|
||||
constructor(label) {
|
||||
|
||||
this.label = "lyr_"
|
||||
|
||||
this.label += (typeof label !== "undefined") ? label : "Unset";
|
||||
console.log(`Constructing Layer ${this.label}, args: ${arguments}`)
|
||||
this.items = [];
|
||||
// console.log(`bg is ${bg} type ${typeof bg}`)
|
||||
|
||||
}
|
||||
|
||||
push(button) {
|
||||
this.items.push(button);
|
||||
}
|
||||
|
||||
setLabel(label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
parseTaps(xy) {
|
||||
this.items.forEach(item => {
|
||||
// // print(item)
|
||||
if (item.was_tapped(xy)) {
|
||||
// pass parent layer to the tapped button
|
||||
item.callback(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
this.items.forEach((item) => {
|
||||
|
||||
item.render();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class BTN_layer extends Layer {
|
||||
|
||||
constructor(label, layout) {
|
||||
|
||||
Layer.call(this, label)
|
||||
|
||||
this.alphabet = (uppercase) ? abc.toUpperCase() : abc;
|
||||
console.log(`Constructing BTN_Layer ${this.label}, layout ${this.layout}`)
|
||||
|
||||
if (layout in points) {
|
||||
|
||||
this.create_layout(layout);
|
||||
|
||||
}
|
||||
else {
|
||||
throw `Invalid layout passed ->[${layout}]`;
|
||||
}
|
||||
|
||||
// // print(this);
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
Layer.prototype.render.call(this);
|
||||
}
|
||||
|
||||
create_layout(layout) {
|
||||
|
||||
console.log(`Creating layout ${layout}`);
|
||||
|
||||
let start_p = 0;
|
||||
|
||||
this.items = this.push_buttons(points[layout], this.alphabet, start_p, chunk_size)
|
||||
|
||||
}
|
||||
|
||||
push_buttons(points, in_string, start_p) {
|
||||
|
||||
items = [];
|
||||
spacer = "" // char interposed b/w the two halves of text per button
|
||||
|
||||
for (let i = 0; i < points.length; i++) {
|
||||
substr = `${in_string.substring(
|
||||
start_p,
|
||||
start_p + chunk_size / 2
|
||||
)}${spacer}${in_string.substring(start_p + chunk_size / 2, start_p + chunk_size)}`;
|
||||
|
||||
btn_label =
|
||||
uppercase === 1
|
||||
? substr.toUpperCase()
|
||||
: substr;
|
||||
|
||||
start_p += chunk_size;
|
||||
|
||||
items.push(
|
||||
new Button(
|
||||
i, // ID of button
|
||||
points[i].x, // left
|
||||
points[i].y, // top
|
||||
btn_label, // text to render in the button
|
||||
box_size.w, // width
|
||||
box_size.h, // height
|
||||
g.theme.bg, // box bg
|
||||
white, // box fill
|
||||
black // text col
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
update_labels(in_string, start_p, chk_size) {
|
||||
// print(`Updating labels | in_string ${in_string} start_p ${start_p} chk_size ${chk_size}`);
|
||||
in_string.replace('\n', ''); // remove newlines just in case
|
||||
|
||||
spacer = "" // char interposed b/w the two halves of text per button
|
||||
|
||||
for (let i = 0; i < this.items.length; i++) {
|
||||
|
||||
item = this.items[i];
|
||||
substr = (chk_size < 3)
|
||||
? in_string.substring(start_p + chk_size * i, start_p + (chk_size * (i + 1)))
|
||||
: `${in_string.substring(
|
||||
start_p + chk_size * i,
|
||||
start_p + chk_size * i + chk_size / 2
|
||||
)}${spacer}${in_string.substring(start_p + chk_size * i + chk_size / 2, start_p + chk_size * i + chk_size)}`;
|
||||
// // print(`(chk_size > 3): ${(chk_size > 3)}`)
|
||||
// print(`Label ${i} -> ${substr}`);
|
||||
item.setLabel(substr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
zoom_in(id) {
|
||||
let start_p = id * chunk_size;
|
||||
// print(`Zooming in | start_p ${start_p}`)
|
||||
if (chunk_size % this.items.length !== 0) {
|
||||
throw `Chunk size [${chunk_size}] does not fit #btns [${this.items.length}]`
|
||||
}
|
||||
subchunk_size = chunk_size / this.items.length;
|
||||
|
||||
substr = this.alphabet.substring(start_p, start_p + chunk_size);
|
||||
// print(`substr ${substr}`);
|
||||
// print(`subchunk_size ${subchunk_size}`);
|
||||
this.update_labels(substr, 0, subchunk_size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Button {
|
||||
constructor(id, x, y, text, w, h, col, bgCol, txtCol, font) {
|
||||
this.id = id;
|
||||
this.label = `btn_${this.id}`;
|
||||
|
||||
this.text = text;
|
||||
this.x1 = x;
|
||||
this.y1 = y;
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
this.col = typeof col !== "undefined" ? col : black;
|
||||
this.bgCol = typeof bgCol !== "undefined" ? bgCol : gray2;
|
||||
this.txtCol = typeof txtCol !== "undefined" ? txtCol : black;
|
||||
// this.font = font;
|
||||
|
||||
this.x2 = this.x1 + this.w;
|
||||
this.y2 = this.y1 + this.h;
|
||||
this.center = {
|
||||
x: (this.x1 + this.x2) / 2,
|
||||
y: (this.y1 + this.y2) / 2,
|
||||
};
|
||||
|
||||
|
||||
console.log(`Constructed button `)
|
||||
// // print(this);
|
||||
}
|
||||
|
||||
render() {
|
||||
// console.log(
|
||||
// `Button ${this.text} -> P1: (${this.x1}, ${this.y1}) | P2: (${this.x2}, ${this.y2})`
|
||||
// );
|
||||
|
||||
g.setColor(this.bgCol);
|
||||
g.fillRect(this.x1, this.y1, this.x2, this.y2);
|
||||
g.setColor(this.col);
|
||||
g.drawRect(this.x1, this.y1, this.x2, this.y2);
|
||||
g.setColor(this.txtCol);
|
||||
|
||||
g.setFontAlign(0, 0).setFont(global_font, font_height);
|
||||
g.drawString(this.text, this.center.x, this.center.y);
|
||||
}
|
||||
|
||||
// short tap callback func
|
||||
callback(parent_layer) {
|
||||
// print(`Tapped button ${this.id}`);
|
||||
|
||||
// this.highlight(); // TODO set up highlighting
|
||||
if (last_layer) {
|
||||
l_text.items[0].text += this.text;
|
||||
// print(`Updated buffer to ${l_text.items[0].text}`)
|
||||
parent_layer.update_labels(parent_layer.alphabet, 0, chunk_size);
|
||||
last_layer = false;
|
||||
}
|
||||
else {
|
||||
parent_layer.zoom_in(this.id);
|
||||
last_layer = true;
|
||||
}
|
||||
}
|
||||
|
||||
was_tapped(xy) {
|
||||
var x = xy.x;
|
||||
var y = xy.y;
|
||||
|
||||
if ((x > this.x1 && x < this.x2) && (y > this.y1 && y < this.y2)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
setLabel(lbl) {
|
||||
// // print(`Button ${this.id}, updating label ${this.text} with ${lbl}`);
|
||||
this.text = lbl;
|
||||
}
|
||||
|
||||
getLabel(lbl) {
|
||||
|
||||
return this.label;
|
||||
}
|
||||
|
||||
highlight() {
|
||||
|
||||
g.setColor(g.theme.bgH);
|
||||
g.fillRect(this.x1, this.y1, this.x2, this.y2);
|
||||
g.setColor(g.theme.fgH);
|
||||
g.drawRect(this.x1, this.y1, this.x2, this.y2);
|
||||
g.setColor(this.fg);
|
||||
|
||||
g.setFontAlign(0, 0).setFont(global_font, font_height);
|
||||
g.drawString(this.text, this.center.x, this.center.y);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TextBox {
|
||||
|
||||
constructor(x, y, text, col) {
|
||||
|
||||
// x and y are the center points
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.text = (typeof text !== undefined) ? text : "Default";
|
||||
this.col = (typeof col !== undefined) ? col : red;
|
||||
|
||||
// console.log(`Constr TextBox ${this.text} -> Center: (${this.x}, ${this.y}) | Col ${this.col}`);
|
||||
}
|
||||
|
||||
render() {
|
||||
// console.log(`Rendering TextBox`)
|
||||
|
||||
var align_center = (0, 1);
|
||||
var align_right = (0, 0);
|
||||
alignment = (g.stringWidth(this.text) < g.getWidth()) ? align_center : align_right;
|
||||
// coords = (g.stringWidth(this.text) < g.getWidth()- 20) ? {x:this.x, y:this.y} : {x:g.getWidth()-border, y:this.y}
|
||||
coords = { x: this.x, y: this.y };
|
||||
g.setColor(this.col);
|
||||
g.setFontAlign(0, 0).setFont(global_font, font_height);
|
||||
g.drawString(this.text, coords.x, coords.y);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Screen refresh *************************************/
|
||||
|
||||
function draw(obj) {
|
||||
console.log("draw()");
|
||||
obj.render();
|
||||
}
|
||||
|
||||
let tickTimer;
|
||||
|
||||
function clearTickTimer() {
|
||||
if (tickTimer) {
|
||||
clearTimeout(tickTimer);
|
||||
tickTimer = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function queueNextTick() {
|
||||
clearTickTimer();
|
||||
tickTimer = setTimeout(tick, 5000);
|
||||
}
|
||||
|
||||
function tick() {
|
||||
console.log("tick");
|
||||
draw(window);
|
||||
// queueNextTick();
|
||||
}
|
||||
|
||||
/* Init **********************************************/
|
||||
|
||||
var window = new Window("abc", red);
|
||||
|
||||
var l_btns = new BTN_layer("btns", "3x2");
|
||||
|
||||
var l_text = new Layer("text"); // black
|
||||
|
||||
var box = new TextBox(
|
||||
_screen_mid,
|
||||
12,
|
||||
editable_buf,
|
||||
white
|
||||
);
|
||||
|
||||
l_text.push(box);
|
||||
|
||||
window.push(l_text);
|
||||
window.push(l_btns);
|
||||
|
||||
// Set up callbacks for touches
|
||||
|
||||
Bangle.on('touch', function (button, xy) {
|
||||
|
||||
window.top_layer().parseTaps(xy);
|
||||
window.render();
|
||||
|
||||
});
|
||||
|
||||
Bangle.on('swipe', function (direction) {
|
||||
|
||||
console.log(`Swipe dir ${direction}`);
|
||||
|
||||
if (direction === -1) { // left
|
||||
|
||||
l_text.items[0].text = l_text.items[0].text.slice(0, -1);
|
||||
|
||||
} else if (direction == 1) { // right
|
||||
|
||||
l_text.items[0].text += ' ';
|
||||
|
||||
}
|
||||
window.render();
|
||||
|
||||
});
|
||||
|
||||
// Clear the screen once, at startup
|
||||
g.clear();
|
||||
|
||||
// Start ticking
|
||||
tick();
|
||||
Loading…
Reference in New Issue