add new module: more_pickers

pull/3455/head
parg-mtwn 2024-06-15 03:35:08 +02:00
parent a038233fa6
commit 78d9eeac27
2 changed files with 291 additions and 0 deletions

198
modules/more_pickers.js Normal file
View File

@ -0,0 +1,198 @@
/* see more_pickers.md for more information */
exports.doublePicker = function (options) {
var menuIcon = "\0\f\f\x81\0\xFF\xFF\xFF\0\0\0\0\x0F\xFF\xFF\xF0\0\0\0\0\xFF\xFF\xFF";
var R = Bangle.appRect;
g.reset().clearRect(R);
g.setFont("12x20").setFontAlign(0, 0).drawString(menuIcon + " " + options.title, R.x + R.w / 2, R.y + 12);
var v_1 = options.value_1;
var v_2 = options.value_2;
function draw() {
g.setColor(g.theme.bg2)
.fillRect(14, 60, 81, 166)
.fillRect(95, 60, 162, 166);
g.setColor(g.theme.fg2)
.fillPoly([47.5, 68, 62.5, 83, 32.5, 83])
.fillPoly([47.5, 158, 62.5, 143, 32.5, 143])
.fillPoly([128.5, 68, 143.5, 83, 113.5, 83])
.fillPoly([128.5, 158, 143.5, 143, 113.5, 143]);
var txt_1 = options.format_1 ? options.format_1(v_1) : v_1;
var txt_2 = options.format_2 ? options.format_2(v_2) : v_2;
g.setFontAlign(0, 0)
.setFontVector(Math.min(30, (R.w - 110) * 100 / g.setFontVector(100).stringWidth(txt_1)))
.drawString(txt_1, 47.5, 113)
.setFontVector(Math.min(30, (R.w - 110) * 100 / g.setFontVector(100).stringWidth(txt_2)))
.drawString(txt_2, 128.5, 113)
.setFontVector(30)
.drawString(options.separator ?? "", 88, 110);
}
function cb(dir, x_part) {
if (dir) {
if (x_part == -1) {
v_1 -= (dir || 1) * (options.step_1 || 1);
if (options.min_1 !== undefined && v_1 < options.min_1) v_1 = options.wrap_1 ? options.max_1 : options.min_1;
if (options.max_1 !== undefined && v_1 > options.max_1) v_1 = options.wrap_1 ? options.min_1 : options.max_1;
} else {
v_2 -= (dir || 1) * (options.step_2 || 1);
if (options.min_2 !== undefined && v_2 < options.min_2) v_2 = options.wrap_2 ? options.max_2 : options.min_2;
if (options.max_2 !== undefined && v_2 > options.max_2) v_2 = options.wrap_2 ? options.min_2 : options.max_2;
}
draw();
} else { // actually selected
options.value_1 = v_1;
options.value_2 = v_2;
if (options.onchange) options.onchange(options.value_1, options.value_2);
options.back(); // redraw original menu
}
}
draw();
var dy = 0;
Bangle.setUI({
mode: "custom",
back: options.back,
remove: options.remove,
redraw: draw,
drag: e => {
dy += e.dy; // after a certain amount of dragging up/down fire cb
if (!e.b) dy = 0;
var x_part;
if (e.x <= 88) {
x_part = -1;
} else {
x_part = 1;
}
while (Math.abs(dy) > 32) {
if (dy > 0) { dy -= 32; cb(1, x_part); }
else { dy += 32; cb(-1, x_part); }
Bangle.buzz(20);
}
},
touch: (_, e) => {
Bangle.buzz(20);
var x_part;
if (e.x <= 88) {
x_part = -1;
} else {
x_part = 1;
}
if (e.y < 82) cb(-1, x_part); // top third
else if (e.y > 142) cb(1, x_part); // bottom third
else cb(); // middle = accept
}
});
}
exports.triplePicker = function (options) {
var menuIcon = "\0\f\f\x81\0\xFF\xFF\xFF\0\0\0\0\x0F\xFF\xFF\xF0\0\0\0\0\xFF\xFF\xFF";
var R = Bangle.appRect;
g.reset().clearRect(R);
g.setFont("12x20").setFontAlign(0, 0).drawString(menuIcon + " " + options.title, R.x + R.w / 2, R.y + 12);
var v_1 = options.value_1;
var v_2 = options.value_2;
var v_3 = options.value_3;
function draw() {
g.setColor(g.theme.bg2)
.fillRect(8, 60, 56, 166)
.fillRect(64, 60, 112, 166)
.fillRect(120, 60, 168, 166);
g.setColor(g.theme.fg2)
.fillPoly([32, 68, 47, 83, 17, 83])
.fillPoly([32, 158, 47, 143, 17, 143])
.fillPoly([88, 68, 103, 83, 73, 83])
.fillPoly([88, 158, 103, 143, 73, 143])
.fillPoly([144, 68, 159, 83, 129, 83])
.fillPoly([144, 158, 159, 143, 129, 143]);
var txt_1 = options.format_1 ? options.format_1(v_1) : v_1;
var txt_2 = options.format_2 ? options.format_2(v_2) : v_2;
var txt_3 = options.format_3 ? options.format_3(v_3) : v_3;
g.setFontAlign(0, 0)
.setFontVector(Math.min(30, (R.w - 130) * 100 / g.setFontVector(100).stringWidth(txt_1)))
.drawString(txt_1, 32, 113)
.setFontVector(Math.min(30, (R.w - 130) * 100 / g.setFontVector(100).stringWidth(txt_2)))
.drawString(txt_2, 88, 113)
.setFontVector(Math.min(30, (R.w - 130) * 100 / g.setFontVector(100).stringWidth(txt_3)))
.drawString(txt_3, 144, 113)
.setFontVector(30)
.drawString(options.separator_1 ?? "", 60, 113)
.drawString(options.separator_2 ?? "", 116, 113);
}
function cb(dir, x_part) {
if (dir) {
if (x_part == -1) {
v_1 -= (dir || 1) * (options.step_1 || 1);
if (options.min_1 !== undefined && v_1 < options.min_1) v_1 = options.wrap_1 ? options.max_1 : options.min_1;
if (options.max_1 !== undefined && v_1 > options.max_1) v_1 = options.wrap_1 ? options.min_1 : options.max_1;
} else if (x_part == 0) {
v_2 -= (dir || 1) * (options.step_2 || 1);
if (options.min_2 !== undefined && v_2 < options.min_2) v_2 = options.wrap_2 ? options.max_2 : options.min_3;
if (options.max_2 !== undefined && v_2 > options.max_2) v_2 = options.wrap_2 ? options.min_2 : options.max_3;
} else {
v_3 -= (dir || 1) * (options.step_3 || 1);
if (options.min_3 !== undefined && v_3 < options.min_3) v_3 = options.wrap_3 ? options.max_3 : options.min_3;
if (options.max_3 !== undefined && v_3 > options.max_3) v_3 = options.wrap_3 ? options.min_3 : options.max_3;
}
draw();
} else { // actually selected
options.value_1 = v_1;
options.value_2 = v_2;
options.value_3 = v_3;
if (options.onchange) options.onchange(options.value_1, options.value_2, options.value_3);
options.back(); // redraw original menu
}
}
draw();
var dy = 0;
Bangle.setUI({
mode: "custom",
back: options.back,
remove: options.remove,
redraw: draw,
drag: e => {
dy += e.dy; // after a certain amount of dragging up/down fire cb
if (!e.b) dy = 0;
var x_part;
if (e.x <= 58) {
x_part = -1;
} else if (58 < e.x && e.x <= 116) {
x_part = 0;
} else {
x_part = 1;
}
while (Math.abs(dy) > 32) {
if (dy > 0) { dy -= 32; cb(1, x_part); }
else { dy += 32; cb(-1, x_part); }
Bangle.buzz(20);
}
},
touch: (_, e) => {
Bangle.buzz(20);
var x_part;
if (e.x <= 58) {
x_part = -1;
} else if (58 < e.x && e.x <= 116) {
x_part = 0;
} else {
x_part = 1;
}
if (e.y < 82) cb(-1, x_part); // top third
else if (e.y > 142) cb(1, x_part); // bottom third
else cb(); // middle = accept
}
});
}

93
modules/more_pickers.md Normal file
View File

@ -0,0 +1,93 @@
# More pickers
This library provides a double picker and a triple picker, similar to the stock picker.
# How to use
**Important:** you need to define a `back` handler that will be called to go back to the previous screen when the user confirms the input or clicks on the back button.
It is possible to define an optionnal custom separator between the values. See examples below.
## Double picker
Example:
```javascript
// example of a formatting function
function pad2(number) {
return (String(number).padStart(2, '0'));
}
var hours = 10;
var minutes = 32;
function showMainMenu() {
E.showMenu({
'Time': function () {
require("more_pickers").doublePicker({
back: showMainMenu,
title: "Time",
separator: ":",
value_1: hours,
min_1: 0, max_1: 23, step_1: 1, wrap_1: true,
value_2: minutes,
min_2: 0, max_2: 59, step_2: 1, wrap_2: true,
format_1: function (v_1) { return (pad2(v_1)); },
format_2: function (v_2) { return (pad2(v_2)); },
onchange: function (v_1, v_2) { hours = v_1; minutes = v_2; }
});
}
});
}
Bangle.loadWidgets();
Bangle.drawWidgets();
showMainMenu();
```
## Triple picker
Example:
```javascript
// example of a formatting function
function pad2(number) {
return (String(number).padStart(2, '0'));
}
var day = 21;
var month = 5;
var year = 2021;
function showMainMenu() {
E.showMenu({
'Date': function () {
require("more_pickers").triplePicker({
back: showMainMenu,
title: "Date",
separator_1: "/",
separator_2: "/",
value_1: day,
min_1: 1, max_1: 31, step_1: 1, wrap_1: true,
value_2: month,
min_2: 1, max_2: 12, step_2: 1, wrap_2: true,
value_3: year,
min_3: 2000, max_3: 2050, step_3: 1, wrap_3: false,
format_1: function (v_1) { return (pad2(v_1)); },
format_2: function (v_2) { return (pad2(v_2)); },
onchange: function (v_1, v_2, v_3) { day = v_1; month = v_2; year = v_3; }
});
}
});
}
Bangle.loadWidgets();
Bangle.drawWidgets();
showMainMenu();