mirror of
https://github.com/opus-tango/B12NumbersV3.git
synced 2026-03-20 12:05:21 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f81325dffd | ||
|
|
8838f763ce | ||
|
|
f160a7fadd | ||
|
|
ceb9c11c9c | ||
|
|
0ad49da001 | ||
|
|
400eb0e78b | ||
|
|
d8297af420 |
@@ -1,178 +0,0 @@
|
|||||||
class MouseHandler {
|
|
||||||
private MouseData md;
|
|
||||||
private LiveMethodRelay[] mrs;
|
|
||||||
|
|
||||||
MouseHandler(MouseData _md) {
|
|
||||||
md = _md;
|
|
||||||
mrs = new LiveMethodRelay[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// PASSTHROUGH FOR MOUSE DATA //
|
|
||||||
float sMouseX(){return md.sMouseX();}
|
|
||||||
float sMouseY(){return md.sMouseY();}
|
|
||||||
float pSMouseX(){return md.pSMouseX();}
|
|
||||||
float pSMouseY(){return md.pSMouseY();}
|
|
||||||
void frameUpdate(PVector offset, float scale){md.update(offset, scale);}// println(mrs.length + " " + millis());}
|
|
||||||
|
|
||||||
|
|
||||||
void addRelay(LiveMethodRelay r) {
|
|
||||||
clean();
|
|
||||||
if(r.getTag() == '\0'){ throw new IllegalArgumentException("MouseHandler only accepts tagged LiveMethodRelays"); }
|
|
||||||
mrs = (LiveMethodRelay[])append(mrs, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clean() {
|
|
||||||
if (mrs.length == 0) return;
|
|
||||||
for (int i = mrs.length -1; i >= 0; i--) {
|
|
||||||
if (!mrs[i].live()) {
|
|
||||||
mrs[i] = mrs[mrs.length - 1];
|
|
||||||
mrs = (LiveMethodRelay[])shorten(mrs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cascade(char tag, float... data) {
|
|
||||||
clean();
|
|
||||||
for (int i = 0; i < mrs.length; i++) {
|
|
||||||
if(mrs[i].getTag() == tag){
|
|
||||||
mrs[i].execute(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MouseData{
|
|
||||||
private PVector offset;
|
|
||||||
private float scale;
|
|
||||||
private float sMouseX;
|
|
||||||
private float sMouseY;
|
|
||||||
private float pSMouseX;
|
|
||||||
private float pSMouseY;
|
|
||||||
|
|
||||||
MouseData(PVector _offset, float _scale){
|
|
||||||
offset = _offset;
|
|
||||||
scale = _scale;
|
|
||||||
sMouseX = (mouseX - offset.x)/scale;
|
|
||||||
sMouseY = (mouseY - offset.y)/scale;
|
|
||||||
pSMouseX = (pmouseX - offset.x)/scale;
|
|
||||||
pSMouseY = (pmouseY - offset.y)/scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
void update(PVector _offset, float _scale){
|
|
||||||
offset = _offset;
|
|
||||||
scale = _scale;
|
|
||||||
sMouseX = (mouseX - offset.x)/scale;
|
|
||||||
sMouseY = (mouseY - offset.y)/scale;
|
|
||||||
pSMouseX = (pmouseX - offset.x)/scale;
|
|
||||||
pSMouseY = (pmouseY - offset.y)/scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
float sMouseX(){return sMouseX;}
|
|
||||||
float sMouseY(){return sMouseY;}
|
|
||||||
float pSMouseX(){return pSMouseX;}
|
|
||||||
float pSMouseY(){return pSMouseY;}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LiveMethodRelay extends MethodRelay {
|
|
||||||
private boolean live;
|
|
||||||
private char tag;
|
|
||||||
|
|
||||||
LiveMethodRelay(Object obj, String name, char _tag, Class... args) {
|
|
||||||
super(obj, name, args);
|
|
||||||
tag = _tag;
|
|
||||||
live = true;
|
|
||||||
}
|
|
||||||
LiveMethodRelay(Object obj, String name, Class... args) {
|
|
||||||
super(obj, name, args);
|
|
||||||
tag = '\0';
|
|
||||||
live = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
char getTag() {return tag;}
|
|
||||||
void setTag(char t) {tag = t;}
|
|
||||||
|
|
||||||
boolean live() {return live;}
|
|
||||||
void kill() {live = false;}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import java.lang.reflect.*;
|
|
||||||
import java.lang.ref.*;
|
|
||||||
/**
|
|
||||||
A class that encapsulates a named method to be invoked.
|
|
||||||
Quark 2015
|
|
||||||
see https://forum.processing.org/two/discussion/13093/how-to-call-function-by-string-content.html
|
|
||||||
Modified to use weak references
|
|
||||||
*/
|
|
||||||
public static class MethodRelay {
|
|
||||||
|
|
||||||
/** The object to handle the draw event */
|
|
||||||
private WeakReference reference = null; // Replaced the original strong reference with a weak reference so that relays will get garbage collected if the object they call get collected
|
|
||||||
//private Object handlerObject = null;
|
|
||||||
/** The method in drawHandlerObject to execute */
|
|
||||||
private Method handlerMethod = null;
|
|
||||||
/** the name of the method to handle the event */
|
|
||||||
private String handlerMethodName;
|
|
||||||
/** An array of classes that represent the function
|
|
||||||
parameters in order */
|
|
||||||
private Class[] parameters = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Register a method that has parameters.
|
|
||||||
parameter obj the object that contains the method to invoke
|
|
||||||
parameter name the name of the method
|
|
||||||
parameter args a comma separated list of
|
|
||||||
*/
|
|
||||||
MethodRelay(Object obj, String name, Class... args) {
|
|
||||||
try {
|
|
||||||
handlerMethodName = name;
|
|
||||||
parameters = args;
|
|
||||||
handlerMethod = obj.getClass().getMethod(handlerMethodName, parameters);
|
|
||||||
reference = new WeakReference(obj);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
println("Unable to find the function -");
|
|
||||||
print(handlerMethodName + "( ");
|
|
||||||
if (parameters != null) {
|
|
||||||
for (Class c : parameters)
|
|
||||||
print(c.getSimpleName() + " ");
|
|
||||||
println(")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Register a method that has no parameters.
|
|
||||||
parameter obj the object that contains the method to invoke
|
|
||||||
parameter name the name of the method
|
|
||||||
*/
|
|
||||||
MethodRelay(Object obj, String name) {
|
|
||||||
this(obj, name, (Class[])null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Execute a paramerterless method
|
|
||||||
*/
|
|
||||||
void execute() {
|
|
||||||
execute((Object[])null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Execute a method with parameters
|
|
||||||
parameter data a comma separated list of values
|
|
||||||
to be passed to the method
|
|
||||||
*/
|
|
||||||
void execute(Object... data) {
|
|
||||||
if (reference.get() != null) {
|
|
||||||
try {
|
|
||||||
handlerMethod.invoke(reference.get(), data);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
println("Error on invoke");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,361 +0,0 @@
|
|||||||
abstract interface Number{
|
|
||||||
abstract PVector getPos();
|
|
||||||
|
|
||||||
abstract void display();
|
|
||||||
}
|
|
||||||
|
|
||||||
class B12Digit implements Number{
|
|
||||||
private byte value;
|
|
||||||
private PVector refPos;
|
|
||||||
|
|
||||||
B12Digit(int _value){
|
|
||||||
if(_value >= 12 || _value < 0){
|
|
||||||
throw new IllegalArgumentException("B12Digit only accepts decimal integers 0 through 11 -- " + _value);
|
|
||||||
}
|
|
||||||
value = byte(_value);
|
|
||||||
refPos = new PVector(0,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
B12Digit(char _c){
|
|
||||||
String valid = "+-*/.:()"; // Defines valid input characters
|
|
||||||
if(!inStr(valid, _c)){ throw new IllegalArgumentException("B12Char only accepts \'+ - * / . :'"); }
|
|
||||||
value = byte(_c);
|
|
||||||
refPos = new PVector(0,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SETTERS
|
|
||||||
B12Digit setRefPos(PVector _refPos){ refPos = _refPos; return this;}
|
|
||||||
B12Digit setRefPos(float _x, float _y){ refPos = new PVector(_x,_y); return this;}
|
|
||||||
B12Digit setValue(int _value){ value = byte(_value); return this;}
|
|
||||||
|
|
||||||
// GETTERS
|
|
||||||
PVector getPos(){ return refPos; }
|
|
||||||
int getValue(){ return value; }
|
|
||||||
boolean isNum(){return value >= 0 && value < 12; }
|
|
||||||
|
|
||||||
// RENDER CHARACTERS
|
|
||||||
void display(){
|
|
||||||
pushMatrix();
|
|
||||||
translate(refPos.x,refPos.y);
|
|
||||||
strokeWeight(1);
|
|
||||||
noFill();
|
|
||||||
stroke(1);
|
|
||||||
ellipseMode(CORNERS);
|
|
||||||
switch(value) {
|
|
||||||
// NUMBERS //
|
|
||||||
case 0:
|
|
||||||
line0(); break;
|
|
||||||
case 1:
|
|
||||||
line1(); break;
|
|
||||||
case 2:
|
|
||||||
line1(); line2(); break;
|
|
||||||
case 3:
|
|
||||||
line1(); line2(); line3(); break;
|
|
||||||
case 4:
|
|
||||||
line4(); break;
|
|
||||||
case 5:
|
|
||||||
line4(); line1(); break;
|
|
||||||
case 6:
|
|
||||||
line4(); line1(); line2(); break;
|
|
||||||
case 7:
|
|
||||||
line4(); line1(); line2(); line3(); break;
|
|
||||||
case 8:
|
|
||||||
line8(); line4(); break;
|
|
||||||
case 9:
|
|
||||||
line8(); line4(); line1(); break;
|
|
||||||
case 10:
|
|
||||||
line8(); line4(); line1(); line2(); break;
|
|
||||||
case 11:
|
|
||||||
line8(); line4(); line1(); line2(); line3(); break;
|
|
||||||
|
|
||||||
// CHARACTERS //
|
|
||||||
case '+':
|
|
||||||
lineMinus(); linePlus(); break;
|
|
||||||
case '-':
|
|
||||||
lineMinus(); break;
|
|
||||||
case '*':
|
|
||||||
lineTimes(); break;
|
|
||||||
case '/':
|
|
||||||
lineMinus(); dotsDiv(); break;
|
|
||||||
case '.':
|
|
||||||
strokeWeight(2); period(); break;
|
|
||||||
case ':':
|
|
||||||
strokeWeight(2); colon(); break;
|
|
||||||
case '(':
|
|
||||||
parenl(); break;
|
|
||||||
case ')':
|
|
||||||
parenr(); break;
|
|
||||||
}
|
|
||||||
popMatrix();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Individual shape components to build any B12 number
|
|
||||||
private void line0(){ quad(4,0,7,-6.5,4,-13,1,-6.5); }// ellipse(0,-13,8,0); }
|
|
||||||
private void line1(){ line(6,0,9,-10); }
|
|
||||||
private void line2(){ line(3,-10,6,0); }
|
|
||||||
private void line3(){ line(0,0,3,-10); }
|
|
||||||
private void line4(){ line(9,-10,2,-13); }
|
|
||||||
private void line8(){ line(2,-13,9,-16); }
|
|
||||||
|
|
||||||
// Individual shape components to build any B12 character
|
|
||||||
private void lineTimes(){ line(4,-7,8,-3); line(4,-3,8,-7); }
|
|
||||||
private void dotsDiv(){ point(6,-8); point(6,-2); }
|
|
||||||
private void lineMinus(){ line(3,-5,9,-5); }
|
|
||||||
private void linePlus(){ line(6,-8,6,-2); }
|
|
||||||
private void period(){ point(5,0); }
|
|
||||||
private void colon(){ point(5,-2); point(5,-8); }
|
|
||||||
private void parenl(){ line(5,-13,3,-6.5); line(5,0,3,-6.5); }
|
|
||||||
private void parenr(){ line(1,-13,3,-6.5); line(1,0,3,-6.5);}
|
|
||||||
|
|
||||||
|
|
||||||
// HELPER FUNCTIONS //
|
|
||||||
private boolean inStr(String st, char _c){
|
|
||||||
try{
|
|
||||||
int x = st.indexOf(_c);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception e){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class B12Int implements Number {
|
|
||||||
private ArrayList<B12Digit> digits;
|
|
||||||
private int value;
|
|
||||||
private PVector pos;
|
|
||||||
private boolean arrayLoaded;
|
|
||||||
private boolean inPosition;
|
|
||||||
private int mode;// Can be RIGHT (39), CENTER (3), or LEFT (37)
|
|
||||||
private int minLen;
|
|
||||||
|
|
||||||
B12Int(int _value){
|
|
||||||
value = _value;
|
|
||||||
pos = new PVector(0,0);
|
|
||||||
arrayLoaded = false;
|
|
||||||
inPosition = false;
|
|
||||||
mode = LEFT;
|
|
||||||
minLen = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GETTERS //
|
|
||||||
int getValue(){ return value; }
|
|
||||||
PVector getPos(){ return pos; }
|
|
||||||
B12Float toFloat(){return new B12Float(float(value)); }
|
|
||||||
|
|
||||||
// SETTERS //
|
|
||||||
B12Int setValue(int _value){ value = _value; arrayLoaded = false; return this;}
|
|
||||||
B12Int setPos(PVector _pos){ pos = _pos.copy(); inPosition = false; return this;}
|
|
||||||
B12Int setPos(float _x, float _y){ pos = new PVector(_x, _y); inPosition = false;return this; }
|
|
||||||
B12Int setMinLen(int i){ minLen = i; return this;}
|
|
||||||
B12Int setAlignMode(int _mode){
|
|
||||||
if(_mode == DECIMAL || _mode == LEFT || _mode == RIGHT){ mode = _mode; }
|
|
||||||
else{ println("Alignment only accepts LEFT, RIGHT, and DECIMAL"); }
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void display(){
|
|
||||||
if(!arrayLoaded){ loadArray(); }
|
|
||||||
if(!inPosition){ positionDigits(); }
|
|
||||||
pushMatrix();
|
|
||||||
translate(pos.x,pos.y);
|
|
||||||
for(int i = 0; i < digits.size(); i++){
|
|
||||||
digits.get(i).display();
|
|
||||||
}
|
|
||||||
popMatrix();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void positionDigits(){
|
|
||||||
if(mode == LEFT || mode == DECIMAL){
|
|
||||||
for(int i = 0; i < digits.size(); i++){
|
|
||||||
digits.get(i).setRefPos((-12 * (i+1)), 0);
|
|
||||||
}
|
|
||||||
}else if(mode == RIGHT){
|
|
||||||
int count = 0;
|
|
||||||
for(int i = digits.size() - 1; i >= 0; i--){
|
|
||||||
digits.get(count).setRefPos((12 * i) + 3, 0);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inPosition = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadArray(){
|
|
||||||
digits = new ArrayList<B12Digit>();
|
|
||||||
int mval = abs(value);
|
|
||||||
if(mval == 0){ digits.add(new B12Digit(0)); }
|
|
||||||
while(mval != 0){
|
|
||||||
if(mval < 12){
|
|
||||||
digits.add(new B12Digit(mval));
|
|
||||||
mval = 0;
|
|
||||||
}else{
|
|
||||||
digits.add(new B12Digit(mval % 12));
|
|
||||||
mval /= 12;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(digits.size() < minLen){
|
|
||||||
digits.add(new B12Digit(0));
|
|
||||||
}
|
|
||||||
if(value < 0){
|
|
||||||
digits.add(new B12Digit('-'));
|
|
||||||
}
|
|
||||||
|
|
||||||
arrayLoaded = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class B12Float implements Number{
|
|
||||||
//private ArrayList<B12Digit> digits;
|
|
||||||
private B12Digit[] digits;
|
|
||||||
private float value;
|
|
||||||
private PVector pos;
|
|
||||||
private boolean arrayLoaded;
|
|
||||||
private boolean inPosition;
|
|
||||||
private int mode;// Can be RIGHT (39), CENTER (3), or LEFT (37)
|
|
||||||
private int places;
|
|
||||||
private int pointPlace;
|
|
||||||
|
|
||||||
B12Float(float _value){
|
|
||||||
value = _value;
|
|
||||||
pos = new PVector(0,0);
|
|
||||||
arrayLoaded = false;
|
|
||||||
inPosition = false;
|
|
||||||
mode = DECIMAL;
|
|
||||||
places = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
float getValue(){ return value; }
|
|
||||||
PVector getPos(){ return pos; }
|
|
||||||
int getPlaces(){ return places; }
|
|
||||||
B12Int toInt(){return new B12Int(int(value));}
|
|
||||||
B12Digit[] getDigits(){ //<>//
|
|
||||||
loadArray();
|
|
||||||
B12Digit[] out = (B12Digit[])reverse(digits);
|
|
||||||
for(int i = out.length-1; i > 0; i--){
|
|
||||||
if(out[i].getValue() == '.'){
|
|
||||||
out = (B12Digit[])shorten(out);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(out[i].getValue() == 0){
|
|
||||||
out = (B12Digit[])shorten(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
B12Float setValue(float _value){ value = _value; arrayLoaded = false; return this;}
|
|
||||||
B12Float setPos(PVector _pos){ pos = _pos.copy(); inPosition = false;return this; }
|
|
||||||
B12Float setPos(float _x, float _y){ pos = new PVector(_x, _y); inPosition = false;return this; }
|
|
||||||
B12Float setPlaces(int _places){
|
|
||||||
if(_places > 12 || _places < 0){
|
|
||||||
throw new IllegalArgumentException("B12Float ncan only display to 12 duodecimal points");
|
|
||||||
}else{
|
|
||||||
places = _places;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
B12Float setAlignMode(int _mode){
|
|
||||||
if(_mode == DECIMAL || _mode == LEFT || _mode == RIGHT){ mode = _mode; }
|
|
||||||
else{ println("Alignment only accepts LEFT, RIGHT, and DECIMAL"); }
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void display(){
|
|
||||||
if(!arrayLoaded){ loadArray(); }
|
|
||||||
if(!inPosition){ positionDigits(); }
|
|
||||||
pushMatrix();
|
|
||||||
translate(pos.x,pos.y);
|
|
||||||
for(int i = 0; i < digits.length; i++){
|
|
||||||
digits[i].display();
|
|
||||||
}
|
|
||||||
popMatrix();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void positionDigits(){
|
|
||||||
int curPos = 0;
|
|
||||||
int count = 0;
|
|
||||||
if(mode == LEFT){
|
|
||||||
for(int i = 0; i < pointPlace; i++){
|
|
||||||
curPos += -12;
|
|
||||||
digits[i].setRefPos(curPos, 0);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
curPos += -8;
|
|
||||||
digits[count].setRefPos(curPos, 0);
|
|
||||||
count++;
|
|
||||||
curPos += -6;
|
|
||||||
digits[count].setRefPos(curPos, 0);
|
|
||||||
count++;
|
|
||||||
|
|
||||||
for(int i = count; i < digits.length; i++){
|
|
||||||
curPos += -12;
|
|
||||||
digits[i].setRefPos(curPos, 0);
|
|
||||||
}
|
|
||||||
}else if(mode == DECIMAL){
|
|
||||||
curPos = -5;
|
|
||||||
digits[pointPlace].setRefPos(curPos,0);
|
|
||||||
curPos += -2;
|
|
||||||
for(int i = pointPlace - 1; i >= 0; i--){
|
|
||||||
curPos += 12;
|
|
||||||
digits[i].setRefPos(curPos,0);
|
|
||||||
}
|
|
||||||
curPos = -2;
|
|
||||||
|
|
||||||
for(int i = pointPlace + 1; i < digits.length; i++){
|
|
||||||
curPos += -12;
|
|
||||||
digits[i].setRefPos(curPos,0);
|
|
||||||
}
|
|
||||||
}else if(mode == RIGHT){
|
|
||||||
for(int i = digits.length - 1; i >= 0; i--){
|
|
||||||
digits[count].setRefPos((12 * i) + 3, 0);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inPosition = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadArray(){
|
|
||||||
//digits = new ArrayList<B12Digit>();
|
|
||||||
digits = new B12Digit[0];
|
|
||||||
B12Digit[] temp = new B12Digit[places];
|
|
||||||
float mval = abs(value);
|
|
||||||
int whole = int(mval);
|
|
||||||
float deci = mval - float(whole);
|
|
||||||
|
|
||||||
for(int i = 0; i < places; i++){
|
|
||||||
deci *= 12;
|
|
||||||
temp[i] = new B12Digit(int(deci));
|
|
||||||
deci -= float(int(deci));
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = places - 1; i >= 0; i--){
|
|
||||||
digits = (B12Digit[])append(digits,temp[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
pointPlace = digits.length;
|
|
||||||
digits = (B12Digit[])append(digits,new B12Digit('.'));
|
|
||||||
|
|
||||||
while(whole > 0){
|
|
||||||
if(whole < 12){
|
|
||||||
digits = (B12Digit[])append(digits,new B12Digit(whole));
|
|
||||||
whole = 0;
|
|
||||||
}else{
|
|
||||||
digits = (B12Digit[])append(digits,new B12Digit(whole % 12));
|
|
||||||
whole /= 12;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(value < 0){
|
|
||||||
digits = (B12Digit[])append(digits,new B12Digit('-'));
|
|
||||||
}
|
|
||||||
|
|
||||||
arrayLoaded = true;
|
|
||||||
inPosition = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
33
B12NumbersV3/B12Button.pde
Normal file
33
B12NumbersV3/B12Button.pde
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
class B12Button extends Button{
|
||||||
|
/*
|
||||||
|
A button that can render a B12Digit instead of text
|
||||||
|
*/
|
||||||
|
B12Digit digit;
|
||||||
|
|
||||||
|
B12Button(MouseHandler _mh, B12Digit _digit){
|
||||||
|
super(_mh);
|
||||||
|
digit = _digit;
|
||||||
|
setData(_digit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GETTERS AND SETTERS //
|
||||||
|
B12Digit getDigit(){ return digit; }
|
||||||
|
B12Button setDigit(B12Digit _digit){ digit = _digit; return this; }
|
||||||
|
|
||||||
|
// Add drawing the B12Digit to the display method
|
||||||
|
@Override
|
||||||
|
void display(){
|
||||||
|
super.display();
|
||||||
|
|
||||||
|
pushMatrix();
|
||||||
|
|
||||||
|
translate(super.pos.x,super.pos.y);
|
||||||
|
switch(super.mode){
|
||||||
|
case CORNER: digit.setPos(super.dim.x/2 - 4, super.dim.y - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
digit.display();
|
||||||
|
|
||||||
|
popMatrix();
|
||||||
|
}
|
||||||
|
}
|
||||||
121
B12NumbersV3/B12Digit.pde
Normal file
121
B12NumbersV3/B12Digit.pde
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
class B12Digit implements Number{
|
||||||
|
// A sngle displayable base 12 digit
|
||||||
|
private byte value; // Using a byte allows storing characters natively in addition to numbers 0 through 11
|
||||||
|
private PVector pos;
|
||||||
|
private color col;
|
||||||
|
|
||||||
|
B12Digit(int _value){
|
||||||
|
if(_value >= 12 || _value < 0){
|
||||||
|
throw new IllegalArgumentException("B12Digit only accepts decimal integers 0 through 11 -- " + _value);
|
||||||
|
}
|
||||||
|
value = byte(_value);
|
||||||
|
pos = new PVector(0,0);
|
||||||
|
col = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
B12Digit(char _c){
|
||||||
|
String valid = "+-*/.:()"; // Defines valid input characters. This can be added to in the future so long as the code to display the digit is added below
|
||||||
|
if(!inStr(valid, _c)){ throw new IllegalArgumentException("B12Char only accepts \'+ - * / . :'"); }
|
||||||
|
value = byte(_c);
|
||||||
|
pos = new PVector(0,0);
|
||||||
|
col = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SETTERS
|
||||||
|
B12Digit setPos(PVector _pos){ pos = _pos; return this;}
|
||||||
|
B12Digit setPos(float _x, float _y){ pos = new PVector(_x,_y); return this;}
|
||||||
|
B12Digit setValue(int _value){ value = byte(_value); return this;}
|
||||||
|
B12Digit setCol(color _col){col = _col; return this;}
|
||||||
|
|
||||||
|
// GETTERS
|
||||||
|
PVector getPos(){ return pos; }
|
||||||
|
int getValue(){ return value; }
|
||||||
|
boolean isNum(){return value >= 0 && value < 12; }
|
||||||
|
color getCol(){return col;}
|
||||||
|
|
||||||
|
// RENDER CHARACTERS
|
||||||
|
void display(){
|
||||||
|
pushMatrix();
|
||||||
|
translate(pos.x,pos.y);
|
||||||
|
strokeWeight(1);
|
||||||
|
noFill();
|
||||||
|
stroke(col);
|
||||||
|
ellipseMode(CORNERS);
|
||||||
|
switch(value) {
|
||||||
|
// NUMBERS //
|
||||||
|
case 0:
|
||||||
|
line0(); break;
|
||||||
|
case 1:
|
||||||
|
line1(); break;
|
||||||
|
case 2:
|
||||||
|
line1(); line2(); break;
|
||||||
|
case 3:
|
||||||
|
line1(); line2(); line3(); break;
|
||||||
|
case 4:
|
||||||
|
line4(); break;
|
||||||
|
case 5:
|
||||||
|
line4(); line1(); break;
|
||||||
|
case 6:
|
||||||
|
line4(); line1(); line2(); break;
|
||||||
|
case 7:
|
||||||
|
line4(); line1(); line2(); line3(); break;
|
||||||
|
case 8:
|
||||||
|
line8(); line4(); break;
|
||||||
|
case 9:
|
||||||
|
line8(); line4(); line1(); break;
|
||||||
|
case 10:
|
||||||
|
line8(); line4(); line1(); line2(); break;
|
||||||
|
case 11:
|
||||||
|
line8(); line4(); line1(); line2(); line3(); break;
|
||||||
|
|
||||||
|
// CHARACTERS //
|
||||||
|
case '+':
|
||||||
|
lineMinus(); linePlus(); break;
|
||||||
|
case '-':
|
||||||
|
lineMinus(); break;
|
||||||
|
case '*':
|
||||||
|
lineTimes(); break;
|
||||||
|
case '/':
|
||||||
|
lineMinus(); dotsDiv(); break;
|
||||||
|
case '.':
|
||||||
|
strokeWeight(2); period(); break;
|
||||||
|
case ':':
|
||||||
|
strokeWeight(2); colon(); break;
|
||||||
|
case '(':
|
||||||
|
parenl(); break;
|
||||||
|
case ')':
|
||||||
|
parenr(); break;
|
||||||
|
}
|
||||||
|
popMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Individual shape components to build any B12 number
|
||||||
|
private void line0(){ quad(4,0,7,-6.5,4,-13,1,-6.5); }// ellipse(0,-13,8,0); }
|
||||||
|
private void line1(){ line(6,0,9,-10); }
|
||||||
|
private void line2(){ line(3,-10,6,0); }
|
||||||
|
private void line3(){ line(0,0,3,-10); }
|
||||||
|
private void line4(){ line(9,-10,2,-13); }
|
||||||
|
private void line8(){ line(2,-13,9,-16); }
|
||||||
|
|
||||||
|
// Individual shape components to build any B12 character
|
||||||
|
private void lineTimes(){ line(4,-7,8,-3); line(4,-3,8,-7); } // multiplication symbol (x)
|
||||||
|
private void dotsDiv(){ point(6,-8); point(6,-2); } // division symbol
|
||||||
|
private void lineMinus(){ line(3,-5,9,-5); }
|
||||||
|
private void linePlus(){ line(6,-8,6,-2); }
|
||||||
|
private void period(){ point(5,0); }
|
||||||
|
private void colon(){ point(5,-2); point(5,-8); }
|
||||||
|
private void parenl(){ line(5,-13,3,-6.5); line(5,0,3,-6.5); }
|
||||||
|
private void parenr(){ line(1,-13,3,-6.5); line(1,0,3,-6.5);}
|
||||||
|
|
||||||
|
|
||||||
|
// HELPER FUNCTIONS //
|
||||||
|
private boolean inStr(String st, char _c){ // Simply returns a boolean whether a character is present in a string
|
||||||
|
try{
|
||||||
|
int x = st.indexOf(_c);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
class B12Expression {
|
class B12Expression {
|
||||||
|
/*
|
||||||
|
The workhorse of the the calculator functionality, B12Expression handles the digits and math
|
||||||
|
It stores only an array of digits, and using only that it can evaluate expressions.
|
||||||
|
*/
|
||||||
private B12Digit[] expression;
|
private B12Digit[] expression;
|
||||||
|
|
||||||
B12Expression(){
|
B12Expression(){
|
||||||
@@ -7,10 +11,10 @@ class B12Expression {
|
|||||||
|
|
||||||
// GETTERS //
|
// GETTERS //
|
||||||
B12Digit getDigit(int index){ return expression[index]; }
|
B12Digit getDigit(int index){ return expression[index]; }
|
||||||
int length(){if(expression == null){return 0;} return expression.length;}
|
int length(){return expression == null ? 0 : expression.length;}
|
||||||
|
|
||||||
// SETTERS //
|
// SETTERS //
|
||||||
B12Expression insertChar(int ind, B12Digit _digit){
|
B12Expression insertChar(int ind, B12Digit _digit){ // Not currently used, but maybe with a future implementation of a cursor?
|
||||||
expression = (B12Digit[])append(expression, _digit); // Add the new digit
|
expression = (B12Digit[])append(expression, _digit); // Add the new digit
|
||||||
if(ind < expression.length - 1){ // Swap new digit
|
if(ind < expression.length - 1){ // Swap new digit
|
||||||
for(int i = expression.length - 1; i > ind; i--){ // Start at second to last digit
|
for(int i = expression.length - 1; i > ind; i--){ // Start at second to last digit
|
||||||
@@ -28,14 +32,13 @@ class B12Expression {
|
|||||||
expression = (B12Digit[])shorten(expression);
|
expression = (B12Digit[])shorten(expression);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
B12Expression clear(){
|
B12Expression clear(){
|
||||||
expression = new B12Digit[0];
|
expression = new B12Digit[0];
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void evaluate(){
|
void evaluate(){
|
||||||
String evalString = parseDigits(); //<>//
|
String evalString = parseDigits();
|
||||||
Expression exp = new ExpressionBuilder(evalString).build();
|
Expression exp = new ExpressionBuilder(evalString).build();
|
||||||
expression = new B12Float((float)exp.evaluate()).setPlaces(12).getDigits();
|
expression = new B12Float((float)exp.evaluate()).setPlaces(12).getDigits();
|
||||||
println(exp.evaluate());
|
println(exp.evaluate());
|
||||||
@@ -43,6 +46,11 @@ class B12Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String parseDigits(){
|
private String parseDigits(){
|
||||||
|
/*
|
||||||
|
Takes the current state of the digit array, converts it to an expression in base 10, and then outputs that as a string.
|
||||||
|
It goes through each element of the array, grouping numeral digits to be converted to complete numbers, and sticking
|
||||||
|
non-numeral character on straight.
|
||||||
|
*/
|
||||||
String valid = "+*-/"; // valid characters to accept
|
String valid = "+*-/"; // valid characters to accept
|
||||||
String evalString = ""; // gets filled with the expression up for evaluation in base 10
|
String evalString = ""; // gets filled with the expression up for evaluation in base 10
|
||||||
B12Digit[] cnum = new B12Digit[0]; // used to sum numbers as the array is parsed
|
B12Digit[] cnum = new B12Digit[0]; // used to sum numbers as the array is parsed
|
||||||
@@ -50,12 +58,12 @@ class B12Expression {
|
|||||||
|
|
||||||
|
|
||||||
// Parse expression[] into a base 10 string that can be evaluated mathematically
|
// Parse expression[] into a base 10 string that can be evaluated mathematically
|
||||||
if(!(expression[expression.length - 1].isNum() || expression[expression.length -1].getValue() == ')' )){throw new IllegalArgumentException("Invalid input");} // check that final character is a number
|
if(!(expression[expression.length - 1].isNum() || expression[expression.length -1].getValue() == ')' )){throw new IllegalArgumentException("Invalid input");} // check that final character is a number or parenthesis
|
||||||
for (int c = expression.length; c >= 0; c--){
|
for (int c = expression.length; c >= 0; c--){ // For each digit in the array, starting at the end
|
||||||
|
|
||||||
int i = c - 1;
|
int i = c - 1; // Convert counter to array index (counter starts one higher than the final index of the array)
|
||||||
|
|
||||||
if (i == -1){ // At the end, add the final number if neccessary
|
if (i == -1){ // At the end of the array, add the final number if neccessary
|
||||||
// add number to string if present
|
// add number to string if present
|
||||||
if(cnum.length != 0 && cfs == false){
|
if(cnum.length != 0 && cfs == false){
|
||||||
B12Int num = (B12Int)convert(cnum,cfs);
|
B12Int num = (B12Int)convert(cnum,cfs);
|
||||||
@@ -116,6 +124,9 @@ class B12Expression {
|
|||||||
|
|
||||||
// HELPER FUNCTIONS //
|
// HELPER FUNCTIONS //
|
||||||
private Number convert(B12Digit[] cnum, boolean isFloat){
|
private Number convert(B12Digit[] cnum, boolean isFloat){
|
||||||
|
/*
|
||||||
|
Converts an array of digits into a B12Int or B12Float respectively
|
||||||
|
*/
|
||||||
if(!isFloat){
|
if(!isFloat){
|
||||||
int out = 0;
|
int out = 0;
|
||||||
for(int i = 0; i < cnum.length; i++){
|
for(int i = 0; i < cnum.length; i++){
|
||||||
159
B12NumbersV3/B12Float.pde
Normal file
159
B12NumbersV3/B12Float.pde
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
class B12Float implements Number{
|
||||||
|
// A displayable base 12 float. The display functionality is not currently used in the app
|
||||||
|
private B12Digit[] digits;
|
||||||
|
private float value;
|
||||||
|
private PVector pos;
|
||||||
|
private boolean arrayLoaded;
|
||||||
|
private boolean inPosition;
|
||||||
|
private int mode;// Can be RIGHT (39), CENTER (3), or LEFT (37)
|
||||||
|
private int places;
|
||||||
|
private int pointPlace;
|
||||||
|
|
||||||
|
B12Float(float _value){
|
||||||
|
value = _value;
|
||||||
|
pos = new PVector(0,0);
|
||||||
|
arrayLoaded = false;
|
||||||
|
inPosition = false;
|
||||||
|
mode = DECIMAL; // Not sure if this is still supported, but should def be discontinued
|
||||||
|
places = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GETTERS //
|
||||||
|
float getValue(){ return value; }
|
||||||
|
PVector getPos(){ return pos; }
|
||||||
|
int getPlaces(){ return places; }
|
||||||
|
B12Int toInt(){return new B12Int(int(value));}
|
||||||
|
B12Digit[] getDigits(){
|
||||||
|
loadArray();
|
||||||
|
B12Digit[] out = (B12Digit[])reverse(digits);
|
||||||
|
for(int i = out.length-1; i > 0; i--){
|
||||||
|
if(out[i].getValue() == '.'){
|
||||||
|
out = (B12Digit[])shorten(out);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(out[i].getValue() == 0){
|
||||||
|
out = (B12Digit[])shorten(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SETTERS //
|
||||||
|
B12Float setValue(float _value){ value = _value; arrayLoaded = false; return this;}
|
||||||
|
B12Float setPos(PVector _pos){ pos = _pos.copy(); inPosition = false;return this; }
|
||||||
|
B12Float setPos(float _x, float _y){ pos = new PVector(_x, _y); inPosition = false;return this; }
|
||||||
|
B12Float setPlaces(int _places){ // Sets number of (dou)decimal places to display
|
||||||
|
if(_places > 12 || _places < 0){
|
||||||
|
throw new IllegalArgumentException("B12Float ncan only display to 12 duodecimal points");
|
||||||
|
}else{
|
||||||
|
places = _places;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
B12Float setAlignMode(int _mode){
|
||||||
|
if(_mode == DECIMAL || _mode == LEFT || _mode == RIGHT){ mode = _mode; }
|
||||||
|
else{ println("Alignment only accepts LEFT, RIGHT, and DECIMAL"); }
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void display(){
|
||||||
|
if(!arrayLoaded){ loadArray(); }
|
||||||
|
if(!inPosition){ positionDigits(); }
|
||||||
|
pushMatrix();
|
||||||
|
translate(pos.x,pos.y);
|
||||||
|
for(int i = 0; i < digits.length; i++){
|
||||||
|
digits[i].display();
|
||||||
|
}
|
||||||
|
popMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Honestly, when it comes to the loading and positioning of digits in the number
|
||||||
|
primitives, I don't remember the details, and since it needs to be rewritten
|
||||||
|
using a different structure anyway, I am not going to document it heavily. The
|
||||||
|
only time it is used in this program is loadDigits being called before the
|
||||||
|
digits are output to the calculator which does its own positioning.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private void positionDigits(){
|
||||||
|
int curPos = 0;
|
||||||
|
int count = 0;
|
||||||
|
if(mode == LEFT){
|
||||||
|
for(int i = 0; i < pointPlace; i++){
|
||||||
|
curPos += -12;
|
||||||
|
digits[i].setPos(curPos, 0);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
curPos += -8;
|
||||||
|
digits[count].setPos(curPos, 0);
|
||||||
|
count++;
|
||||||
|
curPos += -6;
|
||||||
|
digits[count].setPos(curPos, 0);
|
||||||
|
count++;
|
||||||
|
|
||||||
|
for(int i = count; i < digits.length; i++){
|
||||||
|
curPos += -12;
|
||||||
|
digits[i].setPos(curPos, 0);
|
||||||
|
}
|
||||||
|
}else if(mode == DECIMAL){
|
||||||
|
curPos = -5;
|
||||||
|
digits[pointPlace].setPos(curPos,0);
|
||||||
|
curPos += -2;
|
||||||
|
for(int i = pointPlace - 1; i >= 0; i--){
|
||||||
|
curPos += 12;
|
||||||
|
digits[i].setPos(curPos,0);
|
||||||
|
}
|
||||||
|
curPos = -2;
|
||||||
|
|
||||||
|
for(int i = pointPlace + 1; i < digits.length; i++){
|
||||||
|
curPos += -12;
|
||||||
|
digits[i].setPos(curPos,0);
|
||||||
|
}
|
||||||
|
}else if(mode == RIGHT){
|
||||||
|
for(int i = digits.length - 1; i >= 0; i--){
|
||||||
|
digits[count].setPos((12 * i) + 3, 0);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inPosition = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadArray(){
|
||||||
|
//digits = new ArrayList<B12Digit>();
|
||||||
|
digits = new B12Digit[0];
|
||||||
|
B12Digit[] temp = new B12Digit[places];
|
||||||
|
float mval = abs(value);
|
||||||
|
int whole = int(mval);
|
||||||
|
float deci = mval - float(whole);
|
||||||
|
|
||||||
|
for(int i = 0; i < places; i++){
|
||||||
|
deci *= 12;
|
||||||
|
temp[i] = new B12Digit(int(deci));
|
||||||
|
deci -= float(int(deci));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = places - 1; i >= 0; i--){
|
||||||
|
digits = (B12Digit[])append(digits,temp[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointPlace = digits.length;
|
||||||
|
digits = (B12Digit[])append(digits,new B12Digit('.'));
|
||||||
|
|
||||||
|
while(whole > 0){
|
||||||
|
if(whole < 12){
|
||||||
|
digits = (B12Digit[])append(digits,new B12Digit(whole));
|
||||||
|
whole = 0;
|
||||||
|
}else{
|
||||||
|
digits = (B12Digit[])append(digits,new B12Digit(whole % 12));
|
||||||
|
whole /= 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value < 0){
|
||||||
|
digits = (B12Digit[])append(digits,new B12Digit('-'));
|
||||||
|
}
|
||||||
|
|
||||||
|
arrayLoaded = true;
|
||||||
|
inPosition = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
96
B12NumbersV3/B12Int.pde
Normal file
96
B12NumbersV3/B12Int.pde
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
class B12Int implements Number {
|
||||||
|
// A displayable base 12 integer. The display functionality is not currently used in the app
|
||||||
|
private B12Digit[] digits;
|
||||||
|
private int value;
|
||||||
|
private PVector pos;
|
||||||
|
private boolean arrayLoaded; // these bools store the state of the digit array. May no no longer be neccessary
|
||||||
|
private boolean inPosition;
|
||||||
|
private int mode;// Can be RIGHT (39), CENTER (3), or LEFT (37)
|
||||||
|
private int minLen;
|
||||||
|
|
||||||
|
B12Int(int _value){
|
||||||
|
value = _value;
|
||||||
|
pos = new PVector(0,0);
|
||||||
|
arrayLoaded = false;
|
||||||
|
inPosition = false;
|
||||||
|
mode = LEFT;
|
||||||
|
minLen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GETTERS //
|
||||||
|
int getValue(){ return value; }
|
||||||
|
PVector getPos(){ return pos; }
|
||||||
|
B12Float toFloat(){return new B12Float(float(value)); }
|
||||||
|
B12Digit[] getDigits(){ // Returns digits as an array. Used by calculator
|
||||||
|
loadArray();
|
||||||
|
B12Digit[] out = digits;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SETTERS //
|
||||||
|
B12Int setValue(int _value){ value = _value; arrayLoaded = false; return this;}
|
||||||
|
B12Int setPos(PVector _pos){ pos = _pos.copy(); inPosition = false; return this;}
|
||||||
|
B12Int setPos(float _x, float _y){ pos = new PVector(_x, _y); inPosition = false;return this; }
|
||||||
|
B12Int setMinLen(int i){ minLen = i; return this;}
|
||||||
|
B12Int setAlignMode(int _mode){
|
||||||
|
if(_mode == DECIMAL || _mode == LEFT || _mode == RIGHT){ mode = _mode; }
|
||||||
|
else{ println("Alignment only accepts LEFT, RIGHT, and DECIMAL"); }
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void display(){
|
||||||
|
if(!arrayLoaded){ loadArray(); }
|
||||||
|
if(!inPosition){ positionDigits(); }
|
||||||
|
pushMatrix();
|
||||||
|
translate(pos.x,pos.y);
|
||||||
|
for(int i = 0; i < digits.length; i++){
|
||||||
|
digits[i].display();
|
||||||
|
}
|
||||||
|
popMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Honestly, when it comes to the loading and positioning of digits in the number
|
||||||
|
primitives, I don't remember the details, and since it needs to be rewritten
|
||||||
|
using a different structure anyway, I am not going to document it heavily. The
|
||||||
|
only time it is used in this program is loadDigits being called before the
|
||||||
|
digits are output to the calculator which does its own positioning.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private void positionDigits(){ // Sets the position of each individual digit so the number renders properly in relation to its position
|
||||||
|
if(mode == LEFT || mode == CENTER){
|
||||||
|
for(int i = 0; i < digits.length; i++){
|
||||||
|
digits[i].setPos((-12 * (i+1)), 0);
|
||||||
|
}
|
||||||
|
}else if(mode == RIGHT){
|
||||||
|
int count = 0;
|
||||||
|
for(int i = digits.length - 1; i >= 0; i--){
|
||||||
|
digits[count].setPos((12 * i) + 3, 0);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inPosition = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadArray(){ // Loads digits into the digit array converting value to base 12 in the process
|
||||||
|
digits = new B12Digit[0];
|
||||||
|
int mval = abs(value);
|
||||||
|
if(mval == 0){ digits = (B12Digit[])append(digits, new B12Digit(0)); }
|
||||||
|
while(mval != 0){
|
||||||
|
if(mval < 12){
|
||||||
|
digits = (B12Digit[])append(digits, new B12Digit(mval));
|
||||||
|
mval = 0;
|
||||||
|
}else{
|
||||||
|
digits = (B12Digit[])append(digits, new B12Digit(mval % 12));
|
||||||
|
mval /= 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(digits.length < minLen){
|
||||||
|
digits = (B12Digit[])append(digits, new B12Digit(0));
|
||||||
|
}
|
||||||
|
if(value < 0){
|
||||||
|
digits = (B12Digit[])append(digits, new B12Digit('-'));
|
||||||
|
}
|
||||||
|
|
||||||
|
arrayLoaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import net.objecthunter.exp4j.*;
|
import net.objecthunter.exp4j.*; // Math expression evaluation library
|
||||||
|
|
||||||
// B12NumbersV3 //
|
// B12NumbersV3 //
|
||||||
String dbout = new String("");
|
String dbout = new String("");
|
||||||
@@ -7,46 +7,47 @@ PVector offset;
|
|||||||
public static final int DECIMAL = 65;
|
public static final int DECIMAL = 65;
|
||||||
MouseHandler mh; // Mouse event handler
|
MouseHandler mh; // Mouse event handler
|
||||||
|
|
||||||
B12Expression ex;
|
int mode; // State variable
|
||||||
|
|
||||||
|
Button modeButton;
|
||||||
|
ClockApp capp;
|
||||||
Calculator calc;
|
Calculator calc;
|
||||||
Clock clock;
|
|
||||||
Button mode;
|
|
||||||
Button changeTime;
|
|
||||||
STime48 time;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void setup(){
|
void setup(){
|
||||||
size(800,800);
|
// Initialize all the foundation stuff
|
||||||
|
size(800,800); //<>//
|
||||||
offset = new PVector(width/2, height/2);
|
offset = new PVector(width/2, height/2);
|
||||||
time = new STime48();
|
scale = 4;
|
||||||
mh = new MouseHandler(new MouseData(offset, scale));
|
mh = new MouseHandler(new MouseData(offset, scale));
|
||||||
ex = new B12Expression();
|
offset = new PVector(width/2, height/2);
|
||||||
|
|
||||||
calc = new Calculator(mh, ex);
|
mode = 0; // Set initial mode
|
||||||
|
|
||||||
mode = new Button(mh).setPos(new PVector(-20,-100), new PVector(40,20)).setRadius(2).setColor(#8B687F).autoHighlight().setText("Mode").setFunction(new MethodRelay(this, "changeMode"));
|
// Create the apps
|
||||||
|
modeButton = new Button(mh).setPos(new PVector(-13,-offset.y / scale + 2), new PVector(26,10)).setRadius(2).setColor(#8B687F).autoHighlight().setText("Mode").setFunction(new MethodRelay(this, "changeMode"));
|
||||||
|
capp = new ClockApp(mh).setPos(0,-20);
|
||||||
|
calc = new Calculator(mh, new B12Expression());
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(){
|
void draw(){
|
||||||
background(196);
|
background(196);
|
||||||
textAlign(LEFT,TOP);
|
mh.frameUpdate(offset, scale); // Updates scaled and offset mouse position data in mh.md (the MouseData object)
|
||||||
textSize(30);
|
|
||||||
text(dbout,0,0);
|
|
||||||
mh.frameUpdate(offset, scale);
|
|
||||||
stroke(0);
|
|
||||||
strokeWeight(1);
|
|
||||||
//crossMark();
|
|
||||||
translate(offset.x,offset.y);
|
translate(offset.x,offset.y);
|
||||||
scale(scale);
|
scale(scale);
|
||||||
|
|
||||||
if(calc != null) calc.display();
|
modeButton.display();
|
||||||
if(clock != null) clock.display();
|
|
||||||
if(changeTime != null) changeTime.display();
|
|
||||||
mode.display();
|
|
||||||
|
|
||||||
|
|
||||||
|
switch(mode){
|
||||||
|
case 0: // Mode 0 is the clock app
|
||||||
|
capp.display(); break;
|
||||||
|
case 1: // Mode 1 is the calculator app
|
||||||
|
text("Calculator",-1,-offset.y/scale + 28);
|
||||||
|
calc.display(); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mouse Handler code. This is used with buttons to run actions
|
||||||
void mouseClicked(){
|
void mouseClicked(){
|
||||||
// Every clickable element needs check whether the mouse is over it every frame, and if both clicked and mouseover then do action.
|
// Every clickable element needs check whether the mouse is over it every frame, and if both clicked and mouseover then do action.
|
||||||
mh.cascade('c', mh.sMouseX(), mh.sMouseY(), mouseButton);
|
mh.cascade('c', mh.sMouseX(), mh.sMouseY(), mouseButton);
|
||||||
@@ -57,29 +58,6 @@ void mouseReleased(){mh.cascade('r', mh.sMouseX(), mh.sMouseY(), mouseButton);}
|
|||||||
void mouseWheel(MouseEvent event){mh.cascade('w', mh.sMouseX(), mh.sMouseY(), event.getCount());}
|
void mouseWheel(MouseEvent event){mh.cascade('w', mh.sMouseX(), mh.sMouseY(), event.getCount());}
|
||||||
void mouseDragged(){mh.cascade('d', mh.sMouseX(), mh.sMouseY(), mouseButton);}
|
void mouseDragged(){mh.cascade('d', mh.sMouseX(), mh.sMouseY(), mouseButton);}
|
||||||
|
|
||||||
void call(String _call){
|
void changeMode(){ // Changes state variable to switch apps
|
||||||
method(_call);
|
mode = (mode + 1) % 2;
|
||||||
}
|
|
||||||
|
|
||||||
void changeMode(){
|
|
||||||
if(calc == null){
|
|
||||||
clock = null;
|
|
||||||
changeTime = null;
|
|
||||||
calc = new Calculator(mh, ex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
calc = null;
|
|
||||||
clock = new Clock(time).setPos(new PVector(30,0));
|
|
||||||
changeTime = new Button(mh).setPos(new PVector(-40,-60), new PVector(80,20)).setRadius(2).setColor(#B096A7).autoHighlight().setText("Change Time").setFunction(new MethodRelay(clock, "setTime", Time48.class));
|
|
||||||
changeTime.setData(new Time48(12,0,0));
|
|
||||||
Runtime.getRuntime().gc();
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset(){
|
|
||||||
calc.ex.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void crossMark(){
|
|
||||||
line(offset.x,0,offset.x,height);
|
|
||||||
line(0,offset.y,width,offset.y);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,212 +0,0 @@
|
|||||||
class Time48 extends Thread{
|
|
||||||
private int sec48;
|
|
||||||
private int min48;
|
|
||||||
private int hour48;
|
|
||||||
private int tsec48; // Total seconds
|
|
||||||
private boolean initialized;
|
|
||||||
|
|
||||||
// CONSTRUCTORS //
|
|
||||||
// TODO add throwing exceptions to all contructors
|
|
||||||
Time48(){
|
|
||||||
sec48 = 0;
|
|
||||||
min48 = 0;
|
|
||||||
hour48 = 0;
|
|
||||||
tsec48 = 0;
|
|
||||||
initialized = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Time48(int _tsec48){
|
|
||||||
tsec48 = _tsec48;
|
|
||||||
flattenTSec();
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Time48(Time48 t48){
|
|
||||||
tsec48 = t48.tsec();
|
|
||||||
flattenTSec();
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Time48(int h, int m, int s){
|
|
||||||
if(h >= 0 && h < 24){ hour48 = h;}else{throw new IllegalArgumentException();}
|
|
||||||
if(m >= 0 && m < 48){ min48 = m;}else{throw new IllegalArgumentException();}
|
|
||||||
if(s >= 0 && s < 48){ sec48 = s;}else{throw new IllegalArgumentException();}
|
|
||||||
flattenOther();
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GETTERS //
|
|
||||||
int hours(){return hour48;}
|
|
||||||
int mins(){return min48;}
|
|
||||||
int secs(){return sec48;}
|
|
||||||
int tsec(){return tsec48;}
|
|
||||||
int[] t48(){int[] out = {hour48,min48,sec48}; return out;}
|
|
||||||
boolean initialized(){return initialized;}
|
|
||||||
int b10millis(){return int(float(tsec48) * 1562.5);}
|
|
||||||
|
|
||||||
Time48 copy(){ return new Time48(this); }
|
|
||||||
|
|
||||||
// SETTERS //
|
|
||||||
Time48 setHour(int h){
|
|
||||||
if(h < 0 || h >= 24) throw new IllegalArgumentException();
|
|
||||||
hour48 = h;
|
|
||||||
flattenOther();
|
|
||||||
initialized = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
Time48 setMin(int m){
|
|
||||||
if(m < 0 || m >= 48) throw new IllegalArgumentException();
|
|
||||||
min48 = m;
|
|
||||||
flattenOther();
|
|
||||||
initialized = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
Time48 setSec(int s){
|
|
||||||
if(s < 0 || s >= 48) throw new IllegalArgumentException();
|
|
||||||
sec48 = s;
|
|
||||||
flattenOther();
|
|
||||||
initialized = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
Time48 setTsec(int s){ // TODO add exception
|
|
||||||
tsec48 = s;
|
|
||||||
flattenTSec();
|
|
||||||
initialized = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PRIVATE FUNCTIONS //
|
|
||||||
private void flattenTSec(){
|
|
||||||
sec48 = tsec48;
|
|
||||||
min48 = sec48 / 48;
|
|
||||||
hour48 = min48 / 48;
|
|
||||||
|
|
||||||
sec48 -= min48 * 48;
|
|
||||||
min48 -= hour48 * 48;
|
|
||||||
}
|
|
||||||
private void flattenOther(){
|
|
||||||
tsec48 = hour48*48*48 + min48*48 + sec48;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// PLACEHOLDER FUNCTIONS //
|
|
||||||
public void run(){}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class STime48 extends Time48{
|
|
||||||
private int offset; // Time offset in milliseconds
|
|
||||||
private int tmillis; // Actual time at which time was synced to real world in milliseconds
|
|
||||||
private int syncedat; // Offset between the start of the program (when millis() starts counting from) and when the time was last synced
|
|
||||||
private boolean synced;
|
|
||||||
|
|
||||||
STime48(){
|
|
||||||
super();
|
|
||||||
offset = 0;
|
|
||||||
tmillis = 0;
|
|
||||||
syncedat = 0;
|
|
||||||
synced = false;
|
|
||||||
this.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Public sync functions
|
|
||||||
public boolean synced(){return synced;}
|
|
||||||
public STime48 syncTime(){ synced = false; return this; } // Allows syncing after time starts running
|
|
||||||
public STime48 setTime(Time48 _time){
|
|
||||||
// To get offset we subtract where the current clock is from where we want it to be
|
|
||||||
offset = _time.b10millis() - millis() - tmillis + syncedat;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Threaded code
|
|
||||||
@Override
|
|
||||||
public void run(){
|
|
||||||
while(true){
|
|
||||||
if(!synced){sync();}
|
|
||||||
|
|
||||||
delay(1); // MUST USE DELAY OR OFFSET DOES NOT GET CALCULATED
|
|
||||||
if(tmillis + millis() + offset > 86400000){ tmillis -= 86400000; } // Fall over at 00:00
|
|
||||||
setTsec(int((tmillis + millis() - syncedat + offset) / 1562.5)); // Add time at sync, millis since program start, and offset, and subtract the millis between program start and sync (because we're adding millis())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initial sync code
|
|
||||||
private void sync(){
|
|
||||||
int sec = second();
|
|
||||||
tmillis = 0;
|
|
||||||
while(true){
|
|
||||||
if(sec != second()){ // Wait until seconds changes so as to be as accurate as possible
|
|
||||||
tmillis = second()*1000 + minute()*60*1000 + hour()*60*60*1000; // Current time in total millis
|
|
||||||
syncedat = millis();
|
|
||||||
synced = true;
|
|
||||||
println("synced");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Clock {
|
|
||||||
PVector pos;
|
|
||||||
STime48 t48;
|
|
||||||
B12Int hours;
|
|
||||||
B12Int minutes;
|
|
||||||
B12Int seconds;
|
|
||||||
B12Digit sep; // TODO Just deprecated B12Char. Refactor to single array of B12Digits?
|
|
||||||
int tmillis;
|
|
||||||
|
|
||||||
Clock(STime48 _t48) {
|
|
||||||
pos = new PVector(0, 0);
|
|
||||||
t48 = _t48;
|
|
||||||
hours = new B12Int(t48.hours());
|
|
||||||
minutes = new B12Int(t48.mins());
|
|
||||||
seconds = new B12Int(t48.secs());
|
|
||||||
sep = new B12Digit(':'); // Seperation character between time columns
|
|
||||||
|
|
||||||
hours.setMinLen(2);
|
|
||||||
minutes.setMinLen(2); // Format all the ints to show a 0 in the 12s column if they are less than 12
|
|
||||||
seconds.setMinLen(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GETTERS and SETTERS //
|
|
||||||
PVector getPos() { return pos; }
|
|
||||||
Clock setPos(PVector _pos) { pos = _pos.copy(); return this;}
|
|
||||||
Clock setPos(float _x, float _y) { pos = new PVector(_x, _y);return this;}
|
|
||||||
|
|
||||||
Clock setTime(Time48 _time) { t48.setTime(_time); return this;}
|
|
||||||
Clock resetTime() { t48.setTime(new Time48(0)); return this;}
|
|
||||||
|
|
||||||
void display() {
|
|
||||||
if (t48.synced()) {
|
|
||||||
// Time
|
|
||||||
hours.setValue(t48.hours());
|
|
||||||
minutes.setValue(t48.mins());
|
|
||||||
seconds.setValue(t48.secs());
|
|
||||||
|
|
||||||
// Position
|
|
||||||
hours.setPos(-64, 0);
|
|
||||||
minutes.setPos(-32, 0);
|
|
||||||
seconds.setPos(0, 0);
|
|
||||||
B12Digit c1 = new B12Digit(':');
|
|
||||||
B12Digit c2 = new B12Digit(':');
|
|
||||||
c1.setRefPos(-34, 0);
|
|
||||||
c2.setRefPos(-66, 0);
|
|
||||||
|
|
||||||
// Display
|
|
||||||
pushMatrix();
|
|
||||||
translate(pos.x, pos.y);
|
|
||||||
hours.display();
|
|
||||||
c2.display();
|
|
||||||
minutes.display();
|
|
||||||
c1.display();
|
|
||||||
seconds.display();
|
|
||||||
popMatrix();
|
|
||||||
} else {
|
|
||||||
text("fetching current time", pos.x, pos.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -55,8 +55,8 @@ class Button{
|
|||||||
Button setDim(PVector _dim){dim = _dim.copy(); return this;}
|
Button setDim(PVector _dim){dim = _dim.copy(); return this;}
|
||||||
Button setRect(PVector _pos, PVector _dim){pos = _pos; dim = _dim; return this;}
|
Button setRect(PVector _pos, PVector _dim){pos = _pos; dim = _dim; return this;}
|
||||||
Button setRadius(float rad){radius = rad; return this;}
|
Button setRadius(float rad){radius = rad; return this;}
|
||||||
Button setColor(color c){col = c; return this;}
|
Button setColor(color c){colorMode(RGB,255); col = c; return this;}
|
||||||
Button setColor(color c, color h){col = c; highlight = h; return this;}
|
Button setColor(color c, color h){colorMode(RGB,255); col = c; highlight = h; return this;}
|
||||||
Button autoHighlight(){ colorMode(RGB,255); highlight = color(int(red(col) * .85), int(green(col) * .85), int(blue(col) * .85)); return this; }
|
Button autoHighlight(){ colorMode(RGB,255); highlight = color(int(red(col) * .85), int(green(col) * .85), int(blue(col) * .85)); return this; }
|
||||||
Button setHighlight(color h){ highlight = h; return this; }
|
Button setHighlight(color h){ highlight = h; return this; }
|
||||||
Button setText(String t){text = t; return this;}
|
Button setText(String t){text = t; return this;}
|
||||||
@@ -79,7 +79,7 @@ class Button{
|
|||||||
fill(textColor);
|
fill(textColor);
|
||||||
textSize(textSize);
|
textSize(textSize);
|
||||||
if(renderPriority == 0){
|
if(renderPriority == 0){
|
||||||
while(textWidth(text) > dim.x * 0.95){ // WARNING! NOT ROBUST make this a function at some point to allow other rectModes to render properly
|
while(textWidth(text) > dim.x * 0.95){ // WARNING! NOT ROBUST! make this a function at some point to allow other rectModes to render properly
|
||||||
textSize = textSize - 1;
|
textSize = textSize - 1;
|
||||||
textSize(textSize);
|
textSize(textSize);
|
||||||
}
|
}
|
||||||
@@ -96,6 +96,7 @@ class Button{
|
|||||||
if(mouseOver && mouseButton == LEFT){
|
if(mouseOver && mouseButton == LEFT){
|
||||||
//println("clicked" + this);
|
//println("clicked" + this);
|
||||||
function.execute(data);
|
function.execute(data);
|
||||||
|
mouseOver = false; // Very important. Without this a button retains its mouseOver status forever if it stops being displayed, causing it to register being clicked every time the mose is clicked anywhere
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
class Calculator{
|
class Calculator{
|
||||||
|
/* Self contained Calculator widget. Can use an external expression object if data persistance is needed
|
||||||
|
*/
|
||||||
B12Expression ex;
|
B12Expression ex;
|
||||||
MathPad m;
|
MathPad m;
|
||||||
MathDisplay d;
|
MathDisplay d;
|
||||||
108
B12NumbersV3/Clock.pde
Normal file
108
B12NumbersV3/Clock.pde
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
class Clock{
|
||||||
|
/*
|
||||||
|
Self contained clock widget with time setting functionality
|
||||||
|
*/
|
||||||
|
private PVector pos;
|
||||||
|
private MouseHandler mh;
|
||||||
|
private Button[] buttons;
|
||||||
|
private Button setTimeButton;
|
||||||
|
private boolean setTime;
|
||||||
|
private int cursorPos;
|
||||||
|
private STime48 time;
|
||||||
|
private TimeDisplay td;
|
||||||
|
|
||||||
|
Clock(MouseHandler _mh, STime48 _time){
|
||||||
|
pos = new PVector(0,0);
|
||||||
|
mh = _mh;
|
||||||
|
time = _time;
|
||||||
|
td = new TimeDisplay(time);
|
||||||
|
setTime = false;
|
||||||
|
cursorPos = 0;
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
PVector getPos(){return pos;}
|
||||||
|
|
||||||
|
Clock setPos(PVector _pos){pos = _pos.copy(); initialize(); return this;}
|
||||||
|
Clock setPos(float x, float y){pos = new PVector(x,y); initialize(); return this;}
|
||||||
|
|
||||||
|
private void initialize(){
|
||||||
|
buttons = new Button[0];
|
||||||
|
td.setPos(pos.x + 13*4 + 2,pos.y-2);
|
||||||
|
// Create numpad buttons
|
||||||
|
for(int i = 0; i < 12; i++){
|
||||||
|
/* Button position must contain it's absolute position relative to sketch 0,0 for mouseOver to work.
|
||||||
|
This means we cannot translate and traw buttons, we mumst factor the parents position into the
|
||||||
|
absolute position of the button */
|
||||||
|
// x = pos.x + (width + gap) * (i%cols)
|
||||||
|
// y = pos.y + (height + gap) * b2rows - (height + gap) * row
|
||||||
|
PVector bPos = new PVector(pos.x + 22 * int(i%4) - 43,pos.y + 22 * 2 - 22 * floor(i/4) + 2);
|
||||||
|
buttons = (Button[])append(buttons, new B12Button(mh ,new B12Digit(i)).setPos(bPos).setDim(new PVector(20,20)).setFunction(new MethodRelay(this, "addChar", B12Digit.class)).setColor(220,150));
|
||||||
|
}
|
||||||
|
// Create other buttons
|
||||||
|
buttons = (Button[])append(buttons, new Button(mh).setText("Set").setPos(new PVector(pos.x - 43,pos.y + 22*3 + 2)).setDim(new PVector(27,20)).setFunction(new MethodRelay(this, "lockTime")).setColor(220,150));
|
||||||
|
buttons = (Button[])append(buttons, new Button(mh).setText("Clear").setPos(new PVector(pos.x + 29 - 43,pos.y + 22*3 + 2)).setDim(new PVector(28,20)).setFunction(new MethodRelay(this, "clearTime")).setColor(220,150));
|
||||||
|
buttons = (Button[])append(buttons, new Button(mh).setText("Cancel").setPos(new PVector(pos.x + 59 - 43,pos.y + 22*3 + 2)).setDim(new PVector(27,20)).setFunction(new MethodRelay(this, "cancelSetTime")).setColor(220,150));
|
||||||
|
|
||||||
|
setTimeButton = new Button(mh).setText("Set Time").setPos(new PVector(pos.x-21,pos.y + 2)).setDim(new PVector(42,13)).setFunction(new MethodRelay(this, "triggerSetTime")).setColor(220,150);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void addChar(B12Digit digit){
|
||||||
|
// Sets the time based on which button has been pressed, and where the cursor is
|
||||||
|
switch(cursorPos){
|
||||||
|
case 0:
|
||||||
|
td.setTime(new Time48().setHour(digit.getValue() * 12)); cursorPos += 1; break;
|
||||||
|
case 1:
|
||||||
|
td.setTime(new Time48(td.getTime().tsec()).setHour(digit.getValue() + td.getTime().hours())); cursorPos += 2; break;
|
||||||
|
case 3:
|
||||||
|
td.setTime(new Time48(td.getTime().tsec()).setMin(digit.getValue() * 12)); cursorPos += 1; break;
|
||||||
|
case 4:
|
||||||
|
td.setTime(new Time48(td.getTime().tsec()).setMin(digit.getValue() + td.getTime().mins())); cursorPos += 2; break;
|
||||||
|
case 6:
|
||||||
|
td.setTime(new Time48(td.getTime().tsec()).setSec(digit.getValue() * 12)); cursorPos += 1; break;
|
||||||
|
case 7:
|
||||||
|
td.setTime(new Time48(td.getTime().tsec() + digit.getValue())); cursorPos += 1; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the displayed time to a static 0
|
||||||
|
void clearTime(){
|
||||||
|
td.setTime(new Time48(0));
|
||||||
|
cursorPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the synced time to that of the displayed time, then switches the diplayed time back to synced time
|
||||||
|
void lockTime(){
|
||||||
|
time.setTime(td.getTime());
|
||||||
|
td.setTime(time);
|
||||||
|
cursorPos = 0;
|
||||||
|
setTime = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switches mode to setting the time
|
||||||
|
void triggerSetTime(){
|
||||||
|
clearTime();
|
||||||
|
setTime = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancels setting the time, reverting the displayed time back to what synced time was before
|
||||||
|
void cancelSetTime(){
|
||||||
|
td.setTime(time); //<>//
|
||||||
|
cursorPos = 0;
|
||||||
|
setTime = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void display(){
|
||||||
|
if(setTime){
|
||||||
|
for(int i = 0; i < buttons.length; i++){
|
||||||
|
buttons[i].display();
|
||||||
|
}
|
||||||
|
stroke(0);
|
||||||
|
if(cursorPos < 8)line(pos.x - 13 * (4-cursorPos) + 2, pos.y, pos.x - 13 * (4-cursorPos) + 10, pos.y);
|
||||||
|
}else{
|
||||||
|
setTimeButton.display();
|
||||||
|
}
|
||||||
|
td.display();
|
||||||
|
}
|
||||||
|
}
|
||||||
59
B12NumbersV3/ClockApp.pde
Normal file
59
B12NumbersV3/ClockApp.pde
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
class ClockApp{
|
||||||
|
/*
|
||||||
|
A container for positioning, displaying, and switching between a clock, stopwatch, and timer
|
||||||
|
*/
|
||||||
|
private PVector pos;
|
||||||
|
private MouseHandler mh;
|
||||||
|
private Clock clock;
|
||||||
|
private Stopwatch st;
|
||||||
|
private Timer timer;
|
||||||
|
private int mode;
|
||||||
|
private Button cmButton; // change mode button
|
||||||
|
|
||||||
|
ClockApp(MouseHandler _mh){
|
||||||
|
pos = new PVector(0,0);
|
||||||
|
mh = _mh; //<>//
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize(){
|
||||||
|
clock = new Clock(mh, new STime48()).setPos(pos);
|
||||||
|
st = new Stopwatch(mh).setPos(pos);
|
||||||
|
timer = new Timer(mh).setPos(pos);
|
||||||
|
mode = 0;
|
||||||
|
cmButton = new Button(mh).setPos(new PVector(-21,-mh.md.getOffset().y / scale + 18), new PVector(42,10)).setRadius(2).setColor(220,150).setText("Clock Mode").setFunction(new MethodRelay(this, "changeMode"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetPositions(){
|
||||||
|
clock.setPos(pos);
|
||||||
|
st.setPos(pos);
|
||||||
|
timer.setPos(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
PVector getPos(){return pos;}
|
||||||
|
|
||||||
|
ClockApp setPos(PVector _pos){pos = _pos.copy(); resetPositions(); return this;}
|
||||||
|
ClockApp setPos(float x, float y){setPos(new PVector(x,y)); return this;}
|
||||||
|
|
||||||
|
void display(){
|
||||||
|
cmButton.display();
|
||||||
|
fill(0);
|
||||||
|
textSize(10);
|
||||||
|
textAlign(CENTER,BOTTOM);
|
||||||
|
switch(mode){
|
||||||
|
case 0:
|
||||||
|
text("Clock",pos.x -2 ,pos.y-20);
|
||||||
|
clock.display(); break;
|
||||||
|
case 1:
|
||||||
|
text("Stopwatch",pos.x -2 ,pos.y-20);
|
||||||
|
st.display(); break;
|
||||||
|
case 2:
|
||||||
|
text("Timer",pos.x -2 ,pos.y-20);
|
||||||
|
timer.display(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void changeMode(){
|
||||||
|
mode = (mode + 1) % 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
B12NumbersV3/LiveMethodRelay.pde
Normal file
22
B12NumbersV3/LiveMethodRelay.pde
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// LiveMethodRelay is simply a MethodRelay with tags and that can be "killed" so it will be removed from the MouseListener array
|
||||||
|
class LiveMethodRelay extends MethodRelay {
|
||||||
|
private boolean live;
|
||||||
|
private char tag;
|
||||||
|
|
||||||
|
LiveMethodRelay(Object obj, String name, char _tag, Class... args) {
|
||||||
|
super(obj, name, args);
|
||||||
|
tag = _tag;
|
||||||
|
live = true;
|
||||||
|
}
|
||||||
|
LiveMethodRelay(Object obj, String name, Class... args) {
|
||||||
|
super(obj, name, args);
|
||||||
|
tag = '\0';
|
||||||
|
live = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char getTag() {return tag;}
|
||||||
|
void setTag(char t) {tag = t;}
|
||||||
|
|
||||||
|
boolean live() {return live;}
|
||||||
|
void kill() {live = false;}
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
class MathDisplay {
|
class MathDisplay {
|
||||||
|
/*
|
||||||
|
Displays a B12Expression
|
||||||
|
*/
|
||||||
PVector pos;
|
PVector pos;
|
||||||
B12Expression ex;
|
B12Expression ex;
|
||||||
|
|
||||||
@@ -15,7 +18,7 @@ class MathDisplay {
|
|||||||
translate(pos.x,pos.y);
|
translate(pos.x,pos.y);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for(int i = ex.length() - 1; i >= 0 ; i--){
|
for(int i = ex.length() - 1; i >= 0 ; i--){
|
||||||
ex.getDigit(i).setRefPos((-12 * (count+1)), 0);
|
ex.getDigit(i).setPos((-12 * (count+1)), 0);
|
||||||
ex.getDigit(i).display();
|
ex.getDigit(i).display();
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
|
|
||||||
class MathPad{
|
class MathPad{
|
||||||
|
/*
|
||||||
|
Creates and displays a button pad for the calculator input
|
||||||
|
*/
|
||||||
private B12Expression ex;
|
private B12Expression ex;
|
||||||
private MouseHandler mh;
|
private MouseHandler mh;
|
||||||
private Button[] buttons;
|
private Button[] buttons;
|
||||||
@@ -57,36 +59,3 @@ class MathPad{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class B12Button extends Button{
|
|
||||||
B12Digit digit;
|
|
||||||
|
|
||||||
B12Button(MouseHandler _mh, B12Digit _digit){
|
|
||||||
super(_mh);
|
|
||||||
digit = _digit;
|
|
||||||
setData(_digit);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GETTERS AND SETTERS //
|
|
||||||
B12Digit getDigit(){ return digit; }
|
|
||||||
B12Button setDigit(B12Digit _digit){ digit = _digit; return this; }
|
|
||||||
|
|
||||||
// Add drawing the B12Digit to the display method
|
|
||||||
@Override
|
|
||||||
void display(){
|
|
||||||
super.display();
|
|
||||||
|
|
||||||
pushMatrix();
|
|
||||||
|
|
||||||
translate(super.pos.x,super.pos.y);
|
|
||||||
switch(super.mode){
|
|
||||||
case CORNER: digit.setRefPos(super.dim.x/2 - 4, super.dim.y - 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
digit.display();
|
|
||||||
|
|
||||||
popMatrix();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
77
B12NumbersV3/MethodRelay.pde
Normal file
77
B12NumbersV3/MethodRelay.pde
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import java.lang.reflect.*;
|
||||||
|
import java.lang.ref.*;
|
||||||
|
/**
|
||||||
|
A class that encapsulates a named method to be invoked.
|
||||||
|
Quark 2015
|
||||||
|
see https://forum.processing.org/two/discussion/13093/how-to-call-function-by-string-content.html
|
||||||
|
Modified to use weak references. This is the only modification
|
||||||
|
*/
|
||||||
|
public static class MethodRelay {
|
||||||
|
|
||||||
|
/** The object to handle the draw event */
|
||||||
|
private WeakReference reference = null; // Replaced the original strong reference with a weak reference so that relays will not disable garbage collection for the object they reference
|
||||||
|
//private Object handlerObject = null;
|
||||||
|
/** The method in drawHandlerObject to execute */
|
||||||
|
private Method handlerMethod = null;
|
||||||
|
/** the name of the method to handle the event */
|
||||||
|
private String handlerMethodName;
|
||||||
|
/** An array of classes that represent the function
|
||||||
|
parameters in order */
|
||||||
|
private Class[] parameters = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Register a method that has parameters.
|
||||||
|
parameter obj the object that contains the method to invoke
|
||||||
|
parameter name the name of the method
|
||||||
|
parameter args a comma separated list of
|
||||||
|
*/
|
||||||
|
MethodRelay(Object obj, String name, Class... args) {
|
||||||
|
try {
|
||||||
|
handlerMethodName = name;
|
||||||
|
parameters = args;
|
||||||
|
handlerMethod = obj.getClass().getMethod(handlerMethodName, parameters);
|
||||||
|
reference = new WeakReference(obj);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
println("Unable to find the function -");
|
||||||
|
print(handlerMethodName + "( ");
|
||||||
|
if (parameters != null) {
|
||||||
|
for (Class c : parameters)
|
||||||
|
print(c.getSimpleName() + " ");
|
||||||
|
println(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Register a method that has no parameters.
|
||||||
|
parameter obj the object that contains the method to invoke
|
||||||
|
parameter name the name of the method
|
||||||
|
*/
|
||||||
|
MethodRelay(Object obj, String name) {
|
||||||
|
this(obj, name, (Class[])null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Execute a paramerterless method
|
||||||
|
*/
|
||||||
|
void execute() {
|
||||||
|
execute((Object[])null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Execute a method with parameters
|
||||||
|
parameter data a comma separated list of values
|
||||||
|
to be passed to the method
|
||||||
|
*/
|
||||||
|
void execute(Object... data) {
|
||||||
|
if (reference.get() != null) {
|
||||||
|
try {
|
||||||
|
handlerMethod.invoke(reference.get(), data);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
println("Error on invoke");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
B12NumbersV3/MouseData.pde
Normal file
36
B12NumbersV3/MouseData.pde
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
class MouseData{
|
||||||
|
/* MouseData stores properly translated and scaled mouse position for things like buttons
|
||||||
|
*/
|
||||||
|
private PVector offset;
|
||||||
|
private float scale;
|
||||||
|
private float sMouseX;
|
||||||
|
private float sMouseY;
|
||||||
|
private float pSMouseX;
|
||||||
|
private float pSMouseY;
|
||||||
|
|
||||||
|
PVector getOffset(){return offset.copy();}
|
||||||
|
float getScale(){return scale;}
|
||||||
|
|
||||||
|
MouseData(PVector _offset, float _scale){
|
||||||
|
offset = _offset;
|
||||||
|
scale = _scale;
|
||||||
|
sMouseX = (mouseX - offset.x)/scale;
|
||||||
|
sMouseY = (mouseY - offset.y)/scale;
|
||||||
|
pSMouseX = (pmouseX - offset.x)/scale;
|
||||||
|
pSMouseY = (pmouseY - offset.y)/scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(PVector _offset, float _scale){
|
||||||
|
offset = _offset;
|
||||||
|
scale = _scale;
|
||||||
|
sMouseX = (mouseX - offset.x)/scale;
|
||||||
|
sMouseY = (mouseY - offset.y)/scale;
|
||||||
|
pSMouseX = (pmouseX - offset.x)/scale;
|
||||||
|
pSMouseY = (pmouseY - offset.y)/scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
float sMouseX(){return sMouseX;}
|
||||||
|
float sMouseY(){return sMouseY;}
|
||||||
|
float pSMouseX(){return pSMouseX;}
|
||||||
|
float pSMouseY(){return pSMouseY;}
|
||||||
|
}
|
||||||
49
B12NumbersV3/MouseHandler.pde
Normal file
49
B12NumbersV3/MouseHandler.pde
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
class MouseHandler {
|
||||||
|
/* MouseHandler holds the code that listens for mouse actions and passes those
|
||||||
|
calls on to the individual LiveMethodRelay listeners in mrs that have been
|
||||||
|
sent to MouseHandler by buttons and other objects that want to listen for
|
||||||
|
mouse actions.
|
||||||
|
*/
|
||||||
|
private MouseData md;
|
||||||
|
private LiveMethodRelay[] mrs;
|
||||||
|
|
||||||
|
MouseHandler(MouseData _md) {
|
||||||
|
md = _md;
|
||||||
|
mrs = new LiveMethodRelay[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// PASSTHROUGH FOR MOUSE DATA //
|
||||||
|
float sMouseX(){return md.sMouseX();}
|
||||||
|
float sMouseY(){return md.sMouseY();}
|
||||||
|
float pSMouseX(){return md.pSMouseX();}
|
||||||
|
float pSMouseY(){return md.pSMouseY();}
|
||||||
|
void frameUpdate(PVector offset, float scale){md.update(offset, scale);} // Updates the position of the mouse so that it is translated and scaled properly
|
||||||
|
|
||||||
|
// This is used by outside objects to stick a listner in the listener array
|
||||||
|
void addRelay(LiveMethodRelay r) {
|
||||||
|
clean();
|
||||||
|
if(r.getTag() == '\0'){ throw new IllegalArgumentException("MouseHandler only accepts tagged LiveMethodRelays"); }
|
||||||
|
mrs = (LiveMethodRelay[])append(mrs, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean() removes any dead method relays
|
||||||
|
void clean() {
|
||||||
|
if (mrs.length == 0) return;
|
||||||
|
for (int i = mrs.length -1; i >= 0; i--) {
|
||||||
|
if (!mrs[i].live()) {
|
||||||
|
mrs[i] = mrs[mrs.length - 1];
|
||||||
|
mrs = (LiveMethodRelay[])shorten(mrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triggers all method relays marked with the input tag. This is called by the built in mouse function overrides
|
||||||
|
void cascade(char tag, float... data) {
|
||||||
|
clean();
|
||||||
|
for (int i = 0; i < mrs.length; i++) {
|
||||||
|
if(mrs[i].getTag() == tag){
|
||||||
|
mrs[i].execute(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
B12NumbersV3/Number.pde
Normal file
7
B12NumbersV3/Number.pde
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
abstract interface Number{
|
||||||
|
/* Interface allows storing B12Digits, B12Ints, and B12Floats using polymorphism
|
||||||
|
This is used in the calculator code when parsing the input
|
||||||
|
*/
|
||||||
|
abstract PVector getPos();
|
||||||
|
abstract void display();
|
||||||
|
}
|
||||||
53
B12NumbersV3/STime48.pde
Normal file
53
B12NumbersV3/STime48.pde
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
class STime48 extends Time48{
|
||||||
|
/* Synced time class which uses a seperate thread to update time
|
||||||
|
*/
|
||||||
|
private int offset; // Time offset in milliseconds. Used to set STime48 to something other than machine time
|
||||||
|
private int tmillis; // Actual time at which time was synced to real world in milliseconds.
|
||||||
|
private int syncedat; // Offset between the start of the program (when millis() starts counting from) and when the time was last synced
|
||||||
|
private boolean synced; // Stores STime48 status
|
||||||
|
|
||||||
|
STime48(){
|
||||||
|
super();
|
||||||
|
offset = 0;
|
||||||
|
tmillis = 0;
|
||||||
|
syncedat = 0;
|
||||||
|
synced = false;
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public sync functions
|
||||||
|
public boolean synced(){return synced;}
|
||||||
|
public STime48 syncTime(){ synced = false; return this; } // Allows re-syncing after time starts running
|
||||||
|
public STime48 setTime(Time48 _time){
|
||||||
|
// To get offset we subtract where the current clock is from where we want it to be
|
||||||
|
offset = _time.b10millis() - millis() - tmillis + syncedat;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Threaded code
|
||||||
|
@Override
|
||||||
|
public void run(){
|
||||||
|
while(true){
|
||||||
|
if(!synced){sync();}
|
||||||
|
|
||||||
|
delay(1); // MUST USE DELAY OR OFFSET DOES NOT GET CALCULATED - probably caused by some annoying simultaneous memory access glitch
|
||||||
|
if(tmillis + millis() + offset > 86400000){ tmillis -= 86400000; } // Fall over at 00:00
|
||||||
|
setTsec(int((tmillis + millis() - syncedat + offset) / 1562.5)); // Add time at sync, millis since program start, and offset, and subtract the millis between program start and sync (because we're adding millis())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial sync code
|
||||||
|
private void sync(){
|
||||||
|
int sec = second();
|
||||||
|
tmillis = 0;
|
||||||
|
while(true){
|
||||||
|
if(sec != second()){ // Wait until seconds changes so as to be as accurate as possible
|
||||||
|
tmillis = second()*1000 + minute()*60*1000 + hour()*60*60*1000; // Current time in total millis
|
||||||
|
syncedat = millis();
|
||||||
|
synced = true;
|
||||||
|
println("synced");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
B12NumbersV3/Stopwatch.pde
Normal file
59
B12NumbersV3/Stopwatch.pde
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
class Stopwatch{
|
||||||
|
/*
|
||||||
|
A self contained stopwatch widget
|
||||||
|
*/
|
||||||
|
private PVector pos;
|
||||||
|
private MouseHandler mh;
|
||||||
|
private STime48 time;
|
||||||
|
private TimeDisplay td;
|
||||||
|
private Button[] buttons;
|
||||||
|
private boolean running;
|
||||||
|
private color stopCol;
|
||||||
|
|
||||||
|
Stopwatch(MouseHandler _mh){
|
||||||
|
pos = new PVector(0,0);
|
||||||
|
mh = _mh;
|
||||||
|
time = new STime48().setTime(new Time48(0));
|
||||||
|
td = new TimeDisplay(new Time48(0));
|
||||||
|
buttons = new Button[0];
|
||||||
|
running = false;
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
PVector getPos(){return pos;}
|
||||||
|
|
||||||
|
Stopwatch setPos(PVector _pos){pos = _pos.copy(); return this;}
|
||||||
|
Stopwatch setPos(float x, float y){pos = new PVector(x,y); return this;}
|
||||||
|
|
||||||
|
private void initialize(){
|
||||||
|
stopCol = 100;
|
||||||
|
td.setPos(pos.x + 13*4 + 2,pos.y-2).setCol(stopCol);
|
||||||
|
buttons = (Button[])append(buttons, new Button(mh).setText("Start").setPos(new PVector(pos.x - 14 - 30,pos.y + 2)).setDim(new PVector(28,16)).setFunction(new MethodRelay(this, "startt")).setColor(220,150));
|
||||||
|
buttons = (Button[])append(buttons, new Button(mh).setText("Stop").setPos(new PVector(pos.x - 14,pos.y + 2)).setDim(new PVector(28,16)).setFunction(new MethodRelay(this, "stopp")).setColor(220,150));
|
||||||
|
buttons = (Button[])append(buttons, new Button(mh).setText("Reset").setPos(new PVector(pos.x + 16,pos.y + 2)).setDim(new PVector(28,16)).setFunction(new MethodRelay(this, "reset")).setColor(220,150));
|
||||||
|
}
|
||||||
|
|
||||||
|
void display(){
|
||||||
|
for(int i = 0; i < buttons.length; i++){
|
||||||
|
buttons[i].display();
|
||||||
|
}
|
||||||
|
td.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
void startt(){
|
||||||
|
if(running) return;
|
||||||
|
td.setTime(time.setTime(td.getTime())).setCol(0);
|
||||||
|
running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopp(){
|
||||||
|
if(!running )return;
|
||||||
|
td.setTime(new Time48(time)).setCol(stopCol);
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(){
|
||||||
|
td.setTime(new Time48(0)).setCol(stopCol);
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
97
B12NumbersV3/Time48.pde
Normal file
97
B12NumbersV3/Time48.pde
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
class Time48 extends Thread{
|
||||||
|
/* A class which stores time staticly in base 12
|
||||||
|
*/
|
||||||
|
private int sec48;
|
||||||
|
private int min48;
|
||||||
|
private int hour48;
|
||||||
|
private int tsec48; // Total seconds
|
||||||
|
private boolean initialized;
|
||||||
|
|
||||||
|
// CONSTRUCTORS //
|
||||||
|
// TODO add throwing exceptions to all contructors
|
||||||
|
Time48(){
|
||||||
|
sec48 = 0;
|
||||||
|
min48 = 0;
|
||||||
|
hour48 = 0;
|
||||||
|
tsec48 = 0;
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Time48(int _tsec48){
|
||||||
|
tsec48 = _tsec48;
|
||||||
|
flattenTSec();
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Time48(Time48 t48){
|
||||||
|
tsec48 = t48.tsec();
|
||||||
|
flattenTSec();
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Time48(int h, int m, int s){
|
||||||
|
if(h >= 0 && h < 24){ hour48 = h;}else{throw new IllegalArgumentException();}
|
||||||
|
if(m >= 0 && m < 48){ min48 = m;}else{throw new IllegalArgumentException();}
|
||||||
|
if(s >= 0 && s < 48){ sec48 = s;}else{throw new IllegalArgumentException();}
|
||||||
|
flattenOther();
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GETTERS //
|
||||||
|
int hours(){return hour48;}
|
||||||
|
int mins(){return min48;}
|
||||||
|
int secs(){return sec48;}
|
||||||
|
int tsec(){return tsec48;}
|
||||||
|
int[] t48(){int[] out = {hour48,min48,sec48}; return out;}
|
||||||
|
boolean initialized(){return initialized;}
|
||||||
|
int b10millis(){return int(float(tsec48) * 1562.5);}
|
||||||
|
|
||||||
|
Time48 copy(){ return new Time48(this); }
|
||||||
|
|
||||||
|
// SETTERS //
|
||||||
|
Time48 setHour(int h){
|
||||||
|
if(h < 0 || h >= 24) throw new IllegalArgumentException();
|
||||||
|
hour48 = h;
|
||||||
|
flattenOther();
|
||||||
|
initialized = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
Time48 setMin(int m){
|
||||||
|
if(m < 0 || m >= 48) throw new IllegalArgumentException();
|
||||||
|
min48 = m;
|
||||||
|
flattenOther();
|
||||||
|
initialized = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
Time48 setSec(int s){
|
||||||
|
if(s < 0 || s >= 48) throw new IllegalArgumentException();
|
||||||
|
sec48 = s;
|
||||||
|
flattenOther();
|
||||||
|
initialized = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
Time48 setTsec(int s){ // TODO add exception
|
||||||
|
tsec48 = s;
|
||||||
|
flattenTSec();
|
||||||
|
initialized = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRIVATE FUNCTIONS //
|
||||||
|
// The "flatten" functions adjust the class attributes according to whichever attribute has been updated
|
||||||
|
private void flattenTSec(){
|
||||||
|
sec48 = tsec48;
|
||||||
|
min48 = sec48 / 48;
|
||||||
|
hour48 = min48 / 48;
|
||||||
|
|
||||||
|
sec48 -= min48 * 48;
|
||||||
|
min48 -= hour48 * 48;
|
||||||
|
}
|
||||||
|
private void flattenOther(){
|
||||||
|
tsec48 = hour48*48*48 + min48*48 + sec48;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// PLACEHOLDER FUNCTIONS //
|
||||||
|
public void run(){} // This is for STime48 to use threading
|
||||||
|
}
|
||||||
71
B12NumbersV3/TimeDisplay.pde
Normal file
71
B12NumbersV3/TimeDisplay.pde
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
class TimeDisplay {
|
||||||
|
/*
|
||||||
|
Displays a Time48. Can utilize both static Time48 and synced STime48
|
||||||
|
*/
|
||||||
|
private PVector pos;
|
||||||
|
private Time48 t48;
|
||||||
|
private B12Int hours;
|
||||||
|
private B12Int minutes;
|
||||||
|
private B12Int seconds;
|
||||||
|
private B12Digit[] digits;
|
||||||
|
//private int tmillis;
|
||||||
|
private color col;
|
||||||
|
|
||||||
|
TimeDisplay(Time48 _t48) {
|
||||||
|
pos = new PVector(0, 0);
|
||||||
|
t48 = _t48;
|
||||||
|
hours = new B12Int(t48.hours());
|
||||||
|
minutes = new B12Int(t48.mins());
|
||||||
|
seconds = new B12Int(t48.secs());
|
||||||
|
//sep = new B12Digit(':'); // Seperation character between time columns
|
||||||
|
|
||||||
|
hours.setMinLen(2);
|
||||||
|
minutes.setMinLen(2); // Format all the ints to show a 0 in the 12s column if they are less than 12
|
||||||
|
seconds.setMinLen(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GETTERS and SETTERS //
|
||||||
|
PVector getPos() { return pos; }
|
||||||
|
Time48 getTime(){return t48;}
|
||||||
|
color getCol(){return col;}
|
||||||
|
TimeDisplay setPos(PVector _pos) { pos = _pos.copy(); return this;}
|
||||||
|
TimeDisplay setPos(float _x, float _y) { pos = new PVector(_x, _y);return this;}
|
||||||
|
TimeDisplay setCol(color _col){col = _col; return this;}
|
||||||
|
|
||||||
|
TimeDisplay setTime(Time48 _time) {
|
||||||
|
if(_time.getClass() == STime48.class){
|
||||||
|
t48 = _time;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
t48 = _time.copy();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeDisplay resetTime(){ // TODO test this. does it work?
|
||||||
|
if(t48.getClass() != STime48.class){ println("Cannot reset a static time"); return this;}
|
||||||
|
t48 = ((STime48)t48).setTime(new Time48(0));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void display() {
|
||||||
|
digits = new B12Digit[0];
|
||||||
|
if(t48.getClass() == STime48.class){
|
||||||
|
while(!((STime48)t48).synced()){text("fetching current time", pos.x, pos.y);}
|
||||||
|
}
|
||||||
|
// Time
|
||||||
|
hours.setValue(t48.hours());
|
||||||
|
minutes.setValue(t48.mins());
|
||||||
|
seconds.setValue(t48.secs());
|
||||||
|
|
||||||
|
digits = (B12Digit[])concat(digits,seconds.getDigits());
|
||||||
|
digits = (B12Digit[])append(digits,new B12Digit(':'));
|
||||||
|
digits = (B12Digit[])concat(digits,minutes.getDigits());
|
||||||
|
digits = (B12Digit[])append(digits,new B12Digit(':'));
|
||||||
|
digits = (B12Digit[])concat(digits,hours.getDigits());
|
||||||
|
|
||||||
|
// Position
|
||||||
|
for(int i = 0; i < digits.length; i++){
|
||||||
|
digits[i].setPos(i*-13 + pos.x - 13,pos.y).setCol(col).display();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
129
B12NumbersV3/Timer.pde
Normal file
129
B12NumbersV3/Timer.pde
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
class Timer{
|
||||||
|
/*
|
||||||
|
A self contained timer widget
|
||||||
|
Based on Clock, but different enough that it does not inherit it
|
||||||
|
|
||||||
|
Technically sets a synced time to zero, and subtracts whatever that
|
||||||
|
synced time currently happens to be from a target Time48 set to the
|
||||||
|
length of the timer and displays that as it gets smaller.
|
||||||
|
*/
|
||||||
|
PVector pos;
|
||||||
|
MouseHandler mh;
|
||||||
|
Button[] buttons;
|
||||||
|
Button setTimeButton;
|
||||||
|
boolean setTime;
|
||||||
|
int cursorPos;
|
||||||
|
STime48 time;
|
||||||
|
Time48 target;
|
||||||
|
TimeDisplay td;
|
||||||
|
boolean running;
|
||||||
|
|
||||||
|
Timer(MouseHandler _mh){
|
||||||
|
pos = new PVector(0,0);
|
||||||
|
mh = _mh;
|
||||||
|
time = new STime48().setTime(new Time48(0));;
|
||||||
|
target = new Time48(0);
|
||||||
|
td = new TimeDisplay(new Time48(0));
|
||||||
|
setTime = true;
|
||||||
|
running = false;
|
||||||
|
cursorPos = 0;
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
PVector getPos(){return pos;}
|
||||||
|
|
||||||
|
Timer setPos(PVector _pos){pos = _pos.copy(); initialize(); return this;}
|
||||||
|
Timer setPos(float x, float y){pos = new PVector(x,y); initialize(); return this;}
|
||||||
|
|
||||||
|
void initialize(){
|
||||||
|
buttons = new Button[0];
|
||||||
|
td.setPos(pos.x + 13*4 + 2,pos.y-2);
|
||||||
|
// Create numpad buttons
|
||||||
|
for(int i = 0; i < 12; i++){
|
||||||
|
/* Button position must contain it's absolute position relative to sketch 0,0 for mouseOver to work.
|
||||||
|
This means we cannot translate and traw buttons, we mumst factor the parents position into the
|
||||||
|
absolute position of the button */
|
||||||
|
// x = pos.x + (width + gap) * (i%cols)
|
||||||
|
// y = pos.y + (height + gap) * b2rows - (height + gap) * row
|
||||||
|
PVector bPos = new PVector(pos.x + 22 * int(i%4) - 43,pos.y + 22 * 2 - 22 * floor(i/4) + 2);
|
||||||
|
buttons = (Button[])append(buttons, new B12Button(mh ,new B12Digit(i)).setPos(bPos).setDim(new PVector(20,20)).setFunction(new MethodRelay(this, "addChar", B12Digit.class)).setColor(220,150));
|
||||||
|
}
|
||||||
|
// Create other buttons
|
||||||
|
buttons = (Button[])append(buttons, new Button(mh).setText("Start").setPos(new PVector(pos.x - 43,pos.y + 22*3 + 2)).setDim(new PVector(27,20)).setFunction(new MethodRelay(this, "lockTime")).setColor(220,150));
|
||||||
|
buttons = (Button[])append(buttons, new Button(mh).setText("Clear").setPos(new PVector(pos.x + 29 - 43,pos.y + 22*3 + 2)).setDim(new PVector(28,20)).setFunction(new MethodRelay(this, "clearTime")).setColor(220,150));
|
||||||
|
buttons = (Button[])append(buttons, new Button(mh).setText("Cancel").setPos(new PVector(pos.x + 59 - 43,pos.y + 22*3 + 2)).setDim(new PVector(27,20)).setFunction(new MethodRelay(this, "cancelSetTime")).setColor(220,150));
|
||||||
|
|
||||||
|
setTimeButton = new Button(mh).setText("Set Time").setPos(new PVector(pos.x-21,pos.y + 2)).setDim(new PVector(42,13)).setFunction(new MethodRelay(this, "triggerSetTime")).setColor(220,150);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void addChar(B12Digit digit){ // Same as Clock
|
||||||
|
switch(cursorPos){
|
||||||
|
case 0:
|
||||||
|
td.setTime(new Time48().setHour(digit.getValue() * 12)); cursorPos += 1; break;
|
||||||
|
case 1:
|
||||||
|
td.setTime(new Time48(td.getTime().tsec()).setHour(digit.getValue() + td.getTime().hours())); cursorPos += 2; break;
|
||||||
|
case 3:
|
||||||
|
td.setTime(new Time48(td.getTime().tsec()).setMin(digit.getValue() * 12)); cursorPos += 1; break;
|
||||||
|
case 4:
|
||||||
|
td.setTime(new Time48(td.getTime().tsec()).setMin(digit.getValue() + td.getTime().mins())); cursorPos += 2; break;
|
||||||
|
case 6:
|
||||||
|
td.setTime(new Time48(td.getTime().tsec()).setSec(digit.getValue() * 12)); cursorPos += 1; break;
|
||||||
|
case 7:
|
||||||
|
td.setTime(new Time48(td.getTime().tsec() + digit.getValue())); cursorPos += 1; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearTime(){
|
||||||
|
td.setTime(new Time48(0));
|
||||||
|
cursorPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lockTime(){
|
||||||
|
target = new Time48(td.getTime());
|
||||||
|
time.setTime(new Time48(0));
|
||||||
|
td.setTime(new Time48().setTsec(target.tsec() - time.tsec()));
|
||||||
|
cursorPos = 0;
|
||||||
|
setTime = false;
|
||||||
|
running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void triggerSetTime(){
|
||||||
|
clearTime();
|
||||||
|
setTime = true;
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancelSetTime(){
|
||||||
|
//td.setTime(time);
|
||||||
|
cursorPos = 0;
|
||||||
|
setTime = false;
|
||||||
|
running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void display(){
|
||||||
|
if(setTime){
|
||||||
|
for(int i = 0; i < buttons.length; i++){
|
||||||
|
buttons[i].display();
|
||||||
|
}
|
||||||
|
stroke(0);
|
||||||
|
if(cursorPos < 8)line(pos.x - 13 * (4-cursorPos) + 2, pos.y, pos.x - 13 * (4-cursorPos) + 10, pos.y);
|
||||||
|
}else{
|
||||||
|
setTimeButton.display();
|
||||||
|
}
|
||||||
|
if(running == true){ // This counts down when running, but allows displayed time to remain static when setting time
|
||||||
|
td.setTime(new Time48().setTsec(target.tsec() - time.tsec()));
|
||||||
|
}
|
||||||
|
td.display();
|
||||||
|
if(td.getTime().tsec() < 0){ // Display timer done message when timer is done. This also covers up whatever displayed time happens to be (weired negative signs atm)
|
||||||
|
colorMode(RGB,255);
|
||||||
|
fill(255,0,0);
|
||||||
|
rectMode(CORNERS);
|
||||||
|
rect(-13*5,-20,13*5,0);
|
||||||
|
fill(0);
|
||||||
|
textSize(16);
|
||||||
|
textAlign(CENTER,BOTTOM);
|
||||||
|
text("Timer Done!",0,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,19 +3,54 @@
|
|||||||
Beta version of a clock in base 12.
|
Beta version of a clock in base 12.
|
||||||
by Nayan Sawyer
|
by Nayan Sawyer
|
||||||
started Mar 2022
|
started Mar 2022
|
||||||
version 0.2.0.0 April 30 2022
|
version 1.0.0.0 May 20 2022
|
||||||
|
|
||||||
Characters are a variation of Kaktovik Inupiaq numerals
|
Characters are a variation of Kaktovik Inupiaq numerals
|
||||||
reversed and in base 12 instead of 20. I take no credit
|
reversed and in base 12 instead of 20. I take no credit
|
||||||
for the design.
|
for the design.
|
||||||
Includes method relay code by Quark - see https://forum.processing.org/two/discussion/13093/how-to-call-function-by-string-content.html
|
Includes method relay code by Quark - see https://forum.processing.org/two/discussion/13093/how-to-call-function-by-string-content.html
|
||||||
for more details.
|
for more details, and the library exp4j for evaluating mathematical expressions.
|
||||||
|
|
||||||
// TODO switch B12Int from ArrayList to Array
|
// DONE put everything back into seperate tabs
|
||||||
// DONE add actual math evaluation to B12Expression // Once thiss is done we hit version 0.2.0.0 //
|
// DONE fully document everything
|
||||||
// TODO add throwing exceptions to all contructors
|
// TODO add throwing exceptions to all contructors
|
||||||
// MAYBE start clock widget structure
|
// TODO add error message to calculator rather than having it do nothing when it doesn't work
|
||||||
|
// TODO add helper function to B12Expression.convert() so that conversion handles float/int determination on its own
|
||||||
|
// TODO refactor the base code to have ints and floats seperate from the digit and display code, and use a single object to convert a number to digits
|
||||||
// MAYBE add additional operations like power, log, and trig functions
|
// MAYBE add additional operations like power, log, and trig functions
|
||||||
|
// MAYBE add other button highlight options like transparency
|
||||||
|
|
||||||
|
BUGTRACKER
|
||||||
|
- something fishy with button highlight colors
|
||||||
|
- lazy positioning with ClockApp. Should move Stopwatch too
|
||||||
|
- B12Float and B12Int return their digits in opposite orders
|
||||||
|
- B12Float still uses mode DECIMAL
|
||||||
|
- Time48 does not check its inputs in some constructors
|
||||||
|
- renderPriority in Button is only half implemented
|
||||||
|
- negative signs when timer ends (not urgent)
|
||||||
|
|
||||||
|
changelog 1.0.0.0
|
||||||
|
- Finished project to fully working state. Still lots of
|
||||||
|
bugs to squash, and structural problems with the base
|
||||||
|
code of the gui elements. But I don't have time to perfect
|
||||||
|
all of it at the moment. I will probably come back to it
|
||||||
|
in the future.
|
||||||
|
Put everything back into seperate files
|
||||||
|
Finished documentation for final project submission
|
||||||
|
|
||||||
|
changelog 0.2.1.3
|
||||||
|
- Finished timer. All clock apps are now complete. Some
|
||||||
|
assembly required :P
|
||||||
|
|
||||||
|
changelog 0.2.1.2
|
||||||
|
- Finished Stopwatch
|
||||||
|
|
||||||
|
changelog 0.2.1.1
|
||||||
|
- Finished clock implementation
|
||||||
|
|
||||||
|
changelog 0.2.1.0
|
||||||
|
- Changes to the base code and the beginning of the clock
|
||||||
|
applications. File condensing (will be reversed)
|
||||||
|
|
||||||
changelog 0.2.0.0
|
changelog 0.2.0.0
|
||||||
- Evaluating expressions has been fully implemented using
|
- Evaluating expressions has been fully implemented using
|
||||||
|
|||||||
@@ -12,3 +12,5 @@ The time system is now complete with robust syncing and offset features. The bas
|
|||||||
Seconds: there are now 48 seconds in a minute
|
Seconds: there are now 48 seconds in a minute
|
||||||
|
|
||||||
The number system is such that horizontal ticks on top represent multiples of four, and vertical ticks represent multiples of one. Decimal 11 is 2 horizontal ticks, and 3 vertical ticks. However, since the project is in an alpha state, I will not go into great detail at this point.
|
The number system is such that horizontal ticks on top represent multiples of four, and vertical ticks represent multiples of one. Decimal 11 is 2 horizontal ticks, and 3 vertical ticks. However, since the project is in an alpha state, I will not go into great detail at this point.
|
||||||
|
|
||||||
|
The calculator input system is now working. For an early beta demo see [releases](https://github.com/GShadow5/B12NumbersBeta1/releases)
|
||||||
|
|||||||
Reference in New Issue
Block a user