mirror of
https://github.com/opus-tango/B12NumbersV3.git
synced 2026-03-20 12:05:21 +00:00
Compare commits
9 Commits
v0.1.5.8-b
...
v1.0.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f81325dffd | ||
|
|
8838f763ce | ||
|
|
f160a7fadd | ||
|
|
ceb9c11c9c | ||
|
|
0ad49da001 | ||
|
|
400eb0e78b | ||
|
|
7f83b4db59 | ||
|
|
d8297af420 | ||
|
|
a2034715c2 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
windows-amd64
|
||||
@@ -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;
|
||||
//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,346 +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 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));}
|
||||
|
||||
|
||||
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.size(); i++){
|
||||
digits.get(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.get(i).setRefPos(curPos, 0);
|
||||
count++;
|
||||
}
|
||||
|
||||
curPos += -8;
|
||||
digits.get(count).setRefPos(curPos, 0);
|
||||
count++;
|
||||
curPos += -6;
|
||||
digits.get(count).setRefPos(curPos, 0);
|
||||
count++;
|
||||
|
||||
for(int i = count; i < digits.size(); i++){
|
||||
curPos += -12;
|
||||
digits.get(i).setRefPos(curPos, 0);
|
||||
}
|
||||
}else if(mode == DECIMAL){
|
||||
curPos = -5;
|
||||
digits.get(pointPlace).setRefPos(curPos,0);
|
||||
curPos += -2;
|
||||
for(int i = pointPlace - 1; i >= 0; i--){
|
||||
curPos += 12;
|
||||
digits.get(i).setRefPos(curPos,0);
|
||||
}
|
||||
curPos = -2;
|
||||
|
||||
for(int i = pointPlace + 1; i < digits.size(); i++){
|
||||
curPos += -12;
|
||||
digits.get(i).setRefPos(curPos,0);
|
||||
}
|
||||
}else if(mode == RIGHT){
|
||||
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>();
|
||||
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.add(temp[i]);
|
||||
}
|
||||
|
||||
pointPlace = digits.size();
|
||||
digits.add(new B12Digit('.'));
|
||||
|
||||
while(whole > 0){
|
||||
if(whole < 12){
|
||||
digits.add(new B12Digit(whole));
|
||||
whole = 0;
|
||||
}else{
|
||||
digits.add(new B12Digit(whole % 12));
|
||||
whole /= 12;
|
||||
}
|
||||
}
|
||||
|
||||
if(value < 0){
|
||||
digits.add(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 {
|
||||
/*
|
||||
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;
|
||||
|
||||
B12Expression(){
|
||||
@@ -7,10 +11,10 @@ class B12Expression {
|
||||
|
||||
// GETTERS //
|
||||
B12Digit getDigit(int index){ return expression[index]; }
|
||||
int length(){return expression.length;}
|
||||
int length(){return expression == null ? 0 : expression.length;}
|
||||
|
||||
// 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
|
||||
if(ind < expression.length - 1){ // Swap new digit
|
||||
for(int i = expression.length - 1; i > ind; i--){ // Start at second to last digit
|
||||
@@ -28,7 +32,6 @@ class B12Expression {
|
||||
expression = (B12Digit[])shorten(expression);
|
||||
return this;
|
||||
}
|
||||
|
||||
B12Expression clear(){
|
||||
expression = new B12Digit[0];
|
||||
return this;
|
||||
@@ -36,11 +39,18 @@ class B12Expression {
|
||||
|
||||
void evaluate(){
|
||||
String evalString = parseDigits();
|
||||
println(evalString);
|
||||
//<>// //<>//
|
||||
Expression exp = new ExpressionBuilder(evalString).build();
|
||||
expression = new B12Float((float)exp.evaluate()).setPlaces(12).getDigits();
|
||||
println(exp.evaluate());
|
||||
dbout = str((float)exp.evaluate());
|
||||
}
|
||||
|
||||
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 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
|
||||
@@ -48,12 +58,12 @@ class B12Expression {
|
||||
|
||||
|
||||
// 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
|
||||
for (int c = expression.length; c >= 0; c--){
|
||||
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 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
|
||||
if(cnum.length != 0 && cfs == false){
|
||||
B12Int num = (B12Int)convert(cnum,cfs);
|
||||
@@ -114,6 +124,9 @@ class B12Expression {
|
||||
|
||||
// HELPER FUNCTIONS //
|
||||
private Number convert(B12Digit[] cnum, boolean isFloat){
|
||||
/*
|
||||
Converts an array of digits into a B12Int or B12Float respectively
|
||||
*/
|
||||
if(!isFloat){
|
||||
int out = 0;
|
||||
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,45 +1,53 @@
|
||||
import net.objecthunter.exp4j.*; // Math expression evaluation library
|
||||
|
||||
// B12NumbersV3 //
|
||||
float scale = 2;
|
||||
String dbout = new String("");
|
||||
float scale = 4;
|
||||
PVector offset;
|
||||
public static final int DECIMAL = 65;
|
||||
MouseHandler mh; // Mouse event handler
|
||||
|
||||
B12Expression ex;
|
||||
int mode; // State variable
|
||||
|
||||
Button modeButton;
|
||||
ClockApp capp;
|
||||
Calculator calc;
|
||||
Clock clock;
|
||||
Button mode;
|
||||
Button changeTime;
|
||||
STime48 time;
|
||||
|
||||
|
||||
|
||||
void setup(){
|
||||
size(400,400);
|
||||
// Initialize all the foundation stuff
|
||||
size(800,800); //<>//
|
||||
offset = new PVector(width/2, height/2);
|
||||
time = new STime48();
|
||||
scale = 4;
|
||||
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,-width/4), 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(){
|
||||
background(196);
|
||||
mh.frameUpdate(offset, scale);
|
||||
stroke(0);
|
||||
strokeWeight(1);
|
||||
//crossMark();
|
||||
mh.frameUpdate(offset, scale); // Updates scaled and offset mouse position data in mh.md (the MouseData object)
|
||||
translate(offset.x,offset.y);
|
||||
scale(scale);
|
||||
|
||||
if(calc != null) calc.display();
|
||||
if(clock != null) clock.display();
|
||||
if(changeTime != null) changeTime.display();
|
||||
mode.display();
|
||||
modeButton.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(){
|
||||
// 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);
|
||||
@@ -50,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 mouseDragged(){mh.cascade('d', mh.sMouseX(), mh.sMouseY(), mouseButton);}
|
||||
|
||||
void call(String _call){
|
||||
method(_call);
|
||||
}
|
||||
|
||||
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,-width/4 + 30), 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);
|
||||
void changeMode(){ // Changes state variable to switch apps
|
||||
mode = (mode + 1) % 2;
|
||||
}
|
||||
|
||||
@@ -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 setRect(PVector _pos, PVector _dim){pos = _pos; dim = _dim; return this;}
|
||||
Button setRadius(float rad){radius = rad; return this;}
|
||||
Button setColor(color c){col = c; return this;}
|
||||
Button setColor(color c, color h){col = c; highlight = h; return this;}
|
||||
Button setColor(color c){colorMode(RGB,255); col = c; 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 setHighlight(color h){ highlight = h; return this; }
|
||||
Button setText(String t){text = t; return this;}
|
||||
@@ -79,7 +79,7 @@ class Button{
|
||||
fill(textColor);
|
||||
textSize(textSize);
|
||||
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);
|
||||
}
|
||||
@@ -96,6 +96,7 @@ class Button{
|
||||
if(mouseOver && mouseButton == LEFT){
|
||||
//println("clicked" + this);
|
||||
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{
|
||||
/* Self contained Calculator widget. Can use an external expression object if data persistance is needed
|
||||
*/
|
||||
B12Expression ex;
|
||||
MathPad m;
|
||||
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 {
|
||||
/*
|
||||
Displays a B12Expression
|
||||
*/
|
||||
PVector pos;
|
||||
B12Expression ex;
|
||||
|
||||
@@ -15,7 +18,7 @@ class MathDisplay {
|
||||
translate(pos.x,pos.y);
|
||||
int count = 0;
|
||||
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();
|
||||
count++;
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
class MathPad{
|
||||
/*
|
||||
Creates and displays a button pad for the calculator input
|
||||
*/
|
||||
private B12Expression ex;
|
||||
private MouseHandler mh;
|
||||
private Button[] buttons;
|
||||
@@ -41,7 +44,7 @@ class MathPad{
|
||||
buttons = (Button[])append(buttons, new B12Button(mh, new B12Digit('*')).setPos(new PVector(pos.x + 22*4,pos.y)).setFunction(new MethodRelay(this, "addChar", B12Digit.class)).setColor(220,150));
|
||||
buttons = (Button[])append(buttons, new B12Button(mh, new B12Digit('/')).setPos(new PVector(pos.x + 22*4,pos.y + 22)).setFunction(new MethodRelay(this, "addChar", B12Digit.class)).setColor(220,150));
|
||||
buttons = (Button[])append(buttons, new B12Button(mh, new B12Digit('.')).setPos(new PVector(pos.x + 22*4,pos.y + 22*2)).setFunction(new MethodRelay(this, "addChar", B12Digit.class)).setColor(220,150));
|
||||
buttons = (Button[])append(buttons, new Button(mh).setText("Enter").setPos(new PVector(pos.x + 22*4,pos.y + 22*3)).setDim(new PVector(42,20)).setFunction(new MethodRelay(this.ex, "evaluate")).setColor(220,150)); //<>//
|
||||
buttons = (Button[])append(buttons, new Button(mh).setText("Enter").setPos(new PVector(pos.x + 22*4,pos.y + 22*3)).setDim(new PVector(42,20)).setFunction(new MethodRelay(this.ex, "evaluate")).setColor(220,150));
|
||||
buttons = (Button[])append(buttons, new Button(mh).setText("Cl").setPos(new PVector(pos.x + 22*5,pos.y + 22)).setDim(new PVector(20,42)).setFunction(new MethodRelay(this.ex, "clear")).setColor(220,150));
|
||||
buttons = (Button[])append(buttons, new Button(mh).setText("Del").setPos(new PVector(pos.x + 22*5,pos.y)).setDim(new PVector(20,20)).setFunction(new MethodRelay(this.ex, "delete")).setColor(220,150));
|
||||
}
|
||||
@@ -56,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,18 +3,62 @@
|
||||
Beta version of a clock in base 12.
|
||||
by Nayan Sawyer
|
||||
started Mar 2022
|
||||
version 0.1.5.7 April 30 2022
|
||||
version 1.0.0.0 May 20 2022
|
||||
|
||||
Characters are a variation of Kaktovik Inupiaq numerals
|
||||
reversed and in base 12 instead of 20. I take no credit
|
||||
for the design.
|
||||
Includes method relay code be Quark - see https://forum.processing.org/two/discussion/13093/how-to-call-function-by-string-content.html
|
||||
for more details.
|
||||
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, and the library exp4j for evaluating mathematical expressions.
|
||||
|
||||
// TODO add actual math evaluation to B12Expression // Once thiss is done we hit version 0.2.0.0 //
|
||||
// DONE put everything back into seperate tabs
|
||||
// DONE fully document everything
|
||||
// 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 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
|
||||
- Evaluating expressions has been fully implemented using
|
||||
exp4j. Various things have been added to the base classes
|
||||
to support this.
|
||||
|
||||
changelog 0.1.5.8
|
||||
- Tweaks for first beta release for class presentation
|
||||
|
||||
changelog 0.1.5.7
|
||||
- Presentation display setup done.
|
||||
|
||||
@@ -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
|
||||
|
||||
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