From f81325dffde1b8a4333a08a942f64d49f68a766a Mon Sep 17 00:00:00 2001 From: 61616 Date: Fri, 20 May 2022 16:46:13 -0400 Subject: [PATCH] 1.0.0.0 - First full release! --- B12NumbersV3/ActionCodeAll.pde | 178 ---------- B12NumbersV3/B12Base.pde | 370 -------------------- B12NumbersV3/B12Button.pde | 33 ++ B12NumbersV3/B12Digit.pde | 121 +++++++ B12NumbersV3/B12Expression.pde | 165 +++++++++ B12NumbersV3/B12Float.pde | 159 +++++++++ B12NumbersV3/B12Int.pde | 96 +++++ B12NumbersV3/B12NumbersV3.pde | 82 ++--- B12NumbersV3/Button.pde | 8 +- B12NumbersV3/Calculator.pde | 276 +-------------- B12NumbersV3/Clock.pde | 28 +- B12NumbersV3/ClockApp.pde | 118 +++---- B12NumbersV3/LiveMethodRelay.pde | 22 ++ B12NumbersV3/MathDisplay.pde | 27 ++ B12NumbersV3/MathPad.pde | 61 ++++ B12NumbersV3/MethodRelay.pde | 77 ++++ B12NumbersV3/MouseData.pde | 36 ++ B12NumbersV3/MouseHandler.pde | 49 +++ B12NumbersV3/Number.pde | 7 + B12NumbersV3/STime48.pde | 53 +++ B12NumbersV3/Stopwatch.pde | 24 +- B12NumbersV3/{B12TimeAll.pde => Time48.pde} | 59 +--- B12NumbersV3/TimeDisplay.pde | 40 +-- B12NumbersV3/Timer.pde | 17 +- B12NumbersV3/zchangelog.pde | 31 +- 25 files changed, 1065 insertions(+), 1072 deletions(-) delete mode 100644 B12NumbersV3/ActionCodeAll.pde delete mode 100644 B12NumbersV3/B12Base.pde create mode 100644 B12NumbersV3/B12Button.pde create mode 100644 B12NumbersV3/B12Digit.pde create mode 100644 B12NumbersV3/B12Expression.pde create mode 100644 B12NumbersV3/B12Float.pde create mode 100644 B12NumbersV3/B12Int.pde create mode 100644 B12NumbersV3/LiveMethodRelay.pde create mode 100644 B12NumbersV3/MathDisplay.pde create mode 100644 B12NumbersV3/MathPad.pde create mode 100644 B12NumbersV3/MethodRelay.pde create mode 100644 B12NumbersV3/MouseData.pde create mode 100644 B12NumbersV3/MouseHandler.pde create mode 100644 B12NumbersV3/Number.pde create mode 100644 B12NumbersV3/STime48.pde rename B12NumbersV3/{B12TimeAll.pde => Time48.pde} (54%) diff --git a/B12NumbersV3/ActionCodeAll.pde b/B12NumbersV3/ActionCodeAll.pde deleted file mode 100644 index 722648d..0000000 --- a/B12NumbersV3/ActionCodeAll.pde +++ /dev/null @@ -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"); - } - } - } -} diff --git a/B12NumbersV3/B12Base.pde b/B12NumbersV3/B12Base.pde deleted file mode 100644 index 125efc2..0000000 --- a/B12NumbersV3/B12Base.pde +++ /dev/null @@ -1,370 +0,0 @@ -abstract interface Number{ - abstract PVector getPos(); - - abstract void display(); -} - -class B12Digit implements Number{ - private byte value; - private PVector refPos; - 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); - refPos = new PVector(0,0); - col = 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); - col = 0; - } - - // SETTERS - B12Digit setPos(PVector _refPos){ refPos = _refPos; return this;} - B12Digit setPos(float _x, float _y){ refPos = 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 refPos; } - int getValue(){ return value; } - boolean isNum(){return value >= 0 && value < 12; } - color getCol(){return col;} - - // RENDER CHARACTERS - void display(){ - pushMatrix(); - translate(refPos.x,refPos.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); } - 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 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)); } - B12Digit[] getDigits(){ - 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(); - } - - private void positionDigits(){ - if(mode == LEFT || mode == DECIMAL){ - 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(){ - 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; - } -} - - - - -class B12Float implements Number{ - 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].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(); - 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; - } -} diff --git a/B12NumbersV3/B12Button.pde b/B12NumbersV3/B12Button.pde new file mode 100644 index 0000000..f90a2dd --- /dev/null +++ b/B12NumbersV3/B12Button.pde @@ -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(); + } +} diff --git a/B12NumbersV3/B12Digit.pde b/B12NumbersV3/B12Digit.pde new file mode 100644 index 0000000..c1e3f13 --- /dev/null +++ b/B12NumbersV3/B12Digit.pde @@ -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; + } + } +} diff --git a/B12NumbersV3/B12Expression.pde b/B12NumbersV3/B12Expression.pde new file mode 100644 index 0000000..9bdb479 --- /dev/null +++ b/B12NumbersV3/B12Expression.pde @@ -0,0 +1,165 @@ +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(){ + expression = new B12Digit[0]; + } + + // GETTERS // + B12Digit getDigit(int index){ return expression[index]; } + int length(){return expression == null ? 0 : expression.length;} + + // SETTERS // + 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 + expression[i] = expression[i-1]; // Swap object one index below i up into index i + } + expression[ind] = _digit; + } + return this; + } + B12Expression addChar(B12Digit _digit){ + expression = (B12Digit[])append(expression, _digit); + return this; + } + B12Expression delete(){ + expression = (B12Digit[])shorten(expression); + return this; + } + B12Expression clear(){ + expression = new B12Digit[0]; + return this; + } + + void evaluate(){ + String evalString = parseDigits(); + 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 + boolean cfs = false; // float status of currently building number + + + // 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 or parenthesis + for (int c = expression.length; c >= 0; c--){ // For each digit in the array, starting at the end + + 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 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); + evalString = str(num.getValue()) + evalString; + cnum = new B12Digit[0]; + } + else if(cnum.length != 0 && cfs == true){ + B12Float num = (B12Float)convert(cnum,cfs); + evalString = str(num.getValue()) + evalString; + cnum = new B12Digit[0]; + cfs = false; + } + break; + } + + // If there is no number currently being built and the current character is a number start building a new number + if (expression[i].isNum() && cnum.length == 0){ + cnum = (B12Digit[])append(cnum,expression[i]); + } + // If the current character is a number and there IS a number currently being built add the character into the number + else if (expression[i].isNum() && cnum.length != 0){ + cnum = (B12Digit[])append(cnum,expression[i]); + } + else if (expression[i].value == '.' && cnum.length != 0){ + if(cfs == true){throw new IllegalArgumentException("Invalid input");} + cnum = (B12Digit[])append(cnum,expression[i]); + cfs = true; + } + // If any other valid character just add it to the string after making sure to add the last built number if it exists + else if (inStr(valid,char(expression[i].value))){ + + // add number to string if present + if(cnum.length != 0 && cfs == false){ + B12Int num = (B12Int)convert(cnum,cfs); + evalString = str(num.getValue()) + evalString; + cnum = new B12Digit[0]; + } + else if(cnum.length != 0 && cfs == true){ + B12Float num = (B12Float)convert(cnum,cfs); + evalString = str(num.getValue()) + evalString; + cnum = new B12Digit[0]; + cfs = false; + } + + // add character to string + evalString = char(expression[i].getValue()) + evalString; + } + // In all other cases fail + else{ + throw new IllegalArgumentException("Invalid input"); + } + } + + return(evalString); + } + + + + // 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++){ + out += cnum[i].getValue() * pow(12,i); + } + return new B12Int(out); + } + + // Else if float + float out = 0; + int pInd = 0; // Index of period + while(true){// find index of period + if(!cnum[pInd].isNum()){break;} + pInd++; + } + B12Digit[] deci = (B12Digit[])reverse(subset(cnum,0,pInd)); + B12Digit[] whole = (B12Digit[])subset(cnum,pInd+1,cnum.length-pInd-1); + for(int i = 0; i < deci.length; i++){ + out += (float(deci[i].getValue())/12) * pow(10,-i); + } + for(int i = 0; i < whole.length; i++){ + out += float(whole[i].getValue()) * pow(12,i); + } + return new B12Float(out); + } + + boolean inStr(String st, char _c){ + try{ + int x = st.indexOf(_c); + return true; + } + catch (Exception e){ + return false; + } + } +} diff --git a/B12NumbersV3/B12Float.pde b/B12NumbersV3/B12Float.pde new file mode 100644 index 0000000..40fd953 --- /dev/null +++ b/B12NumbersV3/B12Float.pde @@ -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(); + 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; + } +} diff --git a/B12NumbersV3/B12Int.pde b/B12NumbersV3/B12Int.pde new file mode 100644 index 0000000..8494232 --- /dev/null +++ b/B12NumbersV3/B12Int.pde @@ -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; + } +} diff --git a/B12NumbersV3/B12NumbersV3.pde b/B12NumbersV3/B12NumbersV3.pde index 9406784..29e625d 100644 --- a/B12NumbersV3/B12NumbersV3.pde +++ b/B12NumbersV3/B12NumbersV3.pde @@ -1,4 +1,4 @@ -import net.objecthunter.exp4j.*; +import net.objecthunter.exp4j.*; // Math expression evaluation library // B12NumbersV3 // String dbout = new String(""); @@ -7,60 +7,47 @@ 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; -//ClockApp ca; -Clock clock; -Timer timer; -Stopwatch st; - -Button mode; -Button changeTime; -STime48 time; - - - void setup(){ + // 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); - //ca = new ClockApp(mh, time).setPos(-43,0); - clock = new Clock(mh, time);//.setPos(40,20); - timer = new Timer(mh); - st = new Stopwatch(mh); - 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(){ background(196); - textAlign(LEFT,TOP); - textSize(30); - text(dbout,0,0); - 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(); - //clock.display(); - //st.display(); - timer.display(); - //point(-15,0); + 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); @@ -71,25 +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 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); +void changeMode(){ // Changes state variable to switch apps + mode = (mode + 1) % 2; } diff --git a/B12NumbersV3/Button.pde b/B12NumbersV3/Button.pde index 243a48f..1c51c7d 100644 --- a/B12NumbersV3/Button.pde +++ b/B12NumbersV3/Button.pde @@ -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,7 +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 + 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 } } diff --git a/B12NumbersV3/Calculator.pde b/B12NumbersV3/Calculator.pde index 3c540b9..abe211f 100644 --- a/B12NumbersV3/Calculator.pde +++ b/B12NumbersV3/Calculator.pde @@ -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; @@ -16,277 +18,3 @@ class Calculator{ d.display(); } } - -class B12Expression { - private B12Digit[] expression; - - B12Expression(){ - expression = new B12Digit[0]; - } - - // GETTERS // - B12Digit getDigit(int index){ return expression[index]; } - int length(){if(expression == null){return 0;} return expression.length;} - - // SETTERS // - B12Expression insertChar(int ind, B12Digit _digit){ - 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 - expression[i] = expression[i-1]; // Swap object one index below i up into index i - } - expression[ind] = _digit; - } - return this; - } - B12Expression addChar(B12Digit _digit){ - expression = (B12Digit[])append(expression, _digit); - return this; - } - B12Expression delete(){ - expression = (B12Digit[])shorten(expression); - return this; - } - - B12Expression clear(){ - expression = new B12Digit[0]; - return this; - } - - void evaluate(){ - String evalString = parseDigits(); - 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(){ - 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 - boolean cfs = false; // float status of currently building number - - - // 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--){ - - int i = c - 1; - - if (i == -1){ // At the end, add the final number if neccessary - // add number to string if present - if(cnum.length != 0 && cfs == false){ - B12Int num = (B12Int)convert(cnum,cfs); - evalString = str(num.getValue()) + evalString; - cnum = new B12Digit[0]; - } - else if(cnum.length != 0 && cfs == true){ - B12Float num = (B12Float)convert(cnum,cfs); - evalString = str(num.getValue()) + evalString; - cnum = new B12Digit[0]; - cfs = false; - } - break; - } - - // If there is no number currently being built and the current character is a number start building a new number - if (expression[i].isNum() && cnum.length == 0){ - cnum = (B12Digit[])append(cnum,expression[i]); - } - // If the current character is a number and there IS a number currently being built add the character into the number - else if (expression[i].isNum() && cnum.length != 0){ - cnum = (B12Digit[])append(cnum,expression[i]); - } - else if (expression[i].value == '.' && cnum.length != 0){ - if(cfs == true){throw new IllegalArgumentException("Invalid input");} - cnum = (B12Digit[])append(cnum,expression[i]); - cfs = true; - } - // If any other valid character just add it to the string after making sure to add the last built number if it exists - else if (inStr(valid,char(expression[i].value))){ - - // add number to string if present - if(cnum.length != 0 && cfs == false){ - B12Int num = (B12Int)convert(cnum,cfs); - evalString = str(num.getValue()) + evalString; - cnum = new B12Digit[0]; - } - else if(cnum.length != 0 && cfs == true){ - B12Float num = (B12Float)convert(cnum,cfs); - evalString = str(num.getValue()) + evalString; - cnum = new B12Digit[0]; - cfs = false; - } - - // add character to string - evalString = char(expression[i].getValue()) + evalString; - } - // In all other cases fail - else{ - throw new IllegalArgumentException("Invalid input"); - } - } - - return(evalString); - } - - - - // HELPER FUNCTIONS // - private Number convert(B12Digit[] cnum, boolean isFloat){ - if(!isFloat){ - int out = 0; - for(int i = 0; i < cnum.length; i++){ - out += cnum[i].getValue() * pow(12,i); - } - return new B12Int(out); - } - - // Else if float - float out = 0; - int pInd = 0; // Index of period - while(true){// find index of period - if(!cnum[pInd].isNum()){break;} - pInd++; - } - B12Digit[] deci = (B12Digit[])reverse(subset(cnum,0,pInd)); - B12Digit[] whole = (B12Digit[])subset(cnum,pInd+1,cnum.length-pInd-1); - for(int i = 0; i < deci.length; i++){ - out += (float(deci[i].getValue())/12) * pow(10,-i); - } - for(int i = 0; i < whole.length; i++){ - out += float(whole[i].getValue()) * pow(12,i); - } - return new B12Float(out); - } - - boolean inStr(String st, char _c){ - try{ - int x = st.indexOf(_c); - return true; - } - catch (Exception e){ - return false; - } - } -} - -class MathDisplay { - PVector pos; - B12Expression ex; - - MathDisplay(B12Expression _ex){ - ex = _ex; - pos = new PVector(0,0); - } - - PVector getPos(){ return pos; } - MathDisplay setPos(PVector _pos){ pos = _pos; return this;} - - void display(){ - pushMatrix(); - translate(pos.x,pos.y); - int count = 0; - for(int i = ex.length() - 1; i >= 0 ; i--){ - ex.getDigit(i).setPos((-12 * (count+1)), 0); - ex.getDigit(i).display(); - count++; - } - popMatrix(); - } -} - - - -class MathPad{ - private B12Expression ex; - private MouseHandler mh; - private Button[] buttons; - private PVector pos; - - MathPad(MouseHandler _mh, B12Expression _ex){ - ex = _ex; - mh = _mh; - pos = new PVector(0,0); - buttons = new Button[0]; - initialize(); - } - - // GETTERS AND SETTERS // - PVector getPos(){return pos;} - MathPad setPos(PVector _pos){ - pos = _pos.copy(); - initialize(); - return this; - } - - - void initialize(){ - buttons = new Button[0]; - // 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),pos.y + 22 * 3 - 22 * floor(i/4)); - 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 B12Button(mh, new B12Digit('(')).setPos(new PVector(pos.x,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,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*2,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*3,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)).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("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)); - } - - void addChar(B12Digit _digit){ - ex.addChar(_digit); - } - - void display(){ - for(int i = 0; i < buttons.length; i++){ - buttons[i].display(); - } - } -} - - - -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.setPos(super.dim.x/2 - 4, super.dim.y - 2); - } - - digit.display(); - - popMatrix(); - } -} diff --git a/B12NumbersV3/Clock.pde b/B12NumbersV3/Clock.pde index 71badea..ac465b7 100644 --- a/B12NumbersV3/Clock.pde +++ b/B12NumbersV3/Clock.pde @@ -1,12 +1,15 @@ class Clock{ - PVector pos; - MouseHandler mh; - Button[] buttons; - Button setTimeButton; - boolean setTime; - int cursorPos; - STime48 time; - TimeDisplay td; + /* + 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); @@ -20,10 +23,10 @@ class Clock{ PVector getPos(){return pos;} - Clock setPos(PVector _pos){pos = _pos.copy(); return this;} + Clock setPos(PVector _pos){pos = _pos.copy(); initialize(); return this;} Clock setPos(float x, float y){pos = new PVector(x,y); initialize(); return this;} - void initialize(){ + private void initialize(){ buttons = new Button[0]; td.setPos(pos.x + 13*4 + 2,pos.y-2); // Create numpad buttons @@ -46,6 +49,7 @@ class Clock{ } 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; @@ -62,11 +66,13 @@ class Clock{ } } + // 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); @@ -74,11 +80,13 @@ class Clock{ 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; diff --git a/B12NumbersV3/ClockApp.pde b/B12NumbersV3/ClockApp.pde index 1916fcf..97e98c3 100644 --- a/B12NumbersV3/ClockApp.pde +++ b/B12NumbersV3/ClockApp.pde @@ -1,97 +1,59 @@ class ClockApp{ - PVector pos; - MouseHandler mh; - Button[] buttons; - Button modeButton; - Button setTimeButton; - int mode; - boolean setTime; - Time48 time; - TimeDisplay td; + /* + 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, Time48 _time){ + ClockApp(MouseHandler _mh){ pos = new PVector(0,0); - mh = _mh; - time = _time; - td = new TimeDisplay(time); - mode = 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(); return this;} - ClockApp setPos(float x, float y){pos = new PVector(x,y); initialize(); return this;} - ClockApp setMode(int _mode){ - if(_mode == -1){setTime = true; return this;} - mode = _mode; - initialize(); - return this; - } - - void initialize(){ - buttons = new Button[0]; - td.setPos(43,-4); - - if(mode == 0){ - setTimeButton = new Button(mh).setText("Set Time").setPos(new PVector(pos.x+21,pos.y)).setDim(new PVector(42,13)).setFunction(new MethodRelay(this, "setMode", int.class)).setData(-1).setColor(220,150); - - // 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),pos.y + 22 * 2 - 22 * floor(i/4)); - 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,pos.y + 22*3)).setDim(new PVector(42,20)).setFunction(new MethodRelay(this, "evaluate")).setColor(220,150)); - buttons = (Button[])append(buttons, new Button(mh).setText("Clear").setPos(new PVector(pos.x + 22*2,pos.y + 22*3)).setDim(new PVector(42,20)).setFunction(new MethodRelay(this, "clear")).setColor(220,150)); - } - else if(mode == 1){ - } - - } - + 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: - clock(); break; + text("Clock",pos.x -2 ,pos.y-20); + clock.display(); break; case 1: - stopwatch(); break; + text("Stopwatch",pos.x -2 ,pos.y-20); + st.display(); break; case 2: - timer(); break; - case 3: - setTime(); break; + text("Timer",pos.x -2 ,pos.y-20); + timer.display(); break; } } - private void setTime(){ - for(int i = 0; i < buttons.length; i++){ - buttons[i].display(); - } - td.display(); - } - - private void clock(){ - td.display(); - if(!setTime){ - setTimeButton.display(); - return; - } - - for(int i = 0; i < buttons.length; i++){ - buttons[i].display(); - } - } - - private void timer(){ - } - - private void stopwatch(){ - + void changeMode(){ + mode = (mode + 1) % 3; } } diff --git a/B12NumbersV3/LiveMethodRelay.pde b/B12NumbersV3/LiveMethodRelay.pde new file mode 100644 index 0000000..85430bc --- /dev/null +++ b/B12NumbersV3/LiveMethodRelay.pde @@ -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;} +} diff --git a/B12NumbersV3/MathDisplay.pde b/B12NumbersV3/MathDisplay.pde new file mode 100644 index 0000000..af86b9b --- /dev/null +++ b/B12NumbersV3/MathDisplay.pde @@ -0,0 +1,27 @@ +class MathDisplay { + /* + Displays a B12Expression + */ + PVector pos; + B12Expression ex; + + MathDisplay(B12Expression _ex){ + ex = _ex; + pos = new PVector(0,0); + } + + PVector getPos(){ return pos; } + MathDisplay setPos(PVector _pos){ pos = _pos; return this;} + + void display(){ + pushMatrix(); + translate(pos.x,pos.y); + int count = 0; + for(int i = ex.length() - 1; i >= 0 ; i--){ + ex.getDigit(i).setPos((-12 * (count+1)), 0); + ex.getDigit(i).display(); + count++; + } + popMatrix(); + } +} diff --git a/B12NumbersV3/MathPad.pde b/B12NumbersV3/MathPad.pde new file mode 100644 index 0000000..14d85f0 --- /dev/null +++ b/B12NumbersV3/MathPad.pde @@ -0,0 +1,61 @@ +class MathPad{ + /* + Creates and displays a button pad for the calculator input + */ + private B12Expression ex; + private MouseHandler mh; + private Button[] buttons; + private PVector pos; + + MathPad(MouseHandler _mh, B12Expression _ex){ + ex = _ex; + mh = _mh; + pos = new PVector(0,0); + buttons = new Button[0]; + initialize(); + } + + // GETTERS AND SETTERS // + PVector getPos(){return pos;} + MathPad setPos(PVector _pos){ + pos = _pos.copy(); + initialize(); + return this; + } + + + void initialize(){ + buttons = new Button[0]; + // 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),pos.y + 22 * 3 - 22 * floor(i/4)); + 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 B12Button(mh, new B12Digit('(')).setPos(new PVector(pos.x,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,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*2,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*3,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)).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("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)); + } + + void addChar(B12Digit _digit){ + ex.addChar(_digit); + } + + void display(){ + for(int i = 0; i < buttons.length; i++){ + buttons[i].display(); + } + } +} diff --git a/B12NumbersV3/MethodRelay.pde b/B12NumbersV3/MethodRelay.pde new file mode 100644 index 0000000..9bcd482 --- /dev/null +++ b/B12NumbersV3/MethodRelay.pde @@ -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"); + } + } + } +} diff --git a/B12NumbersV3/MouseData.pde b/B12NumbersV3/MouseData.pde new file mode 100644 index 0000000..08643a0 --- /dev/null +++ b/B12NumbersV3/MouseData.pde @@ -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;} +} diff --git a/B12NumbersV3/MouseHandler.pde b/B12NumbersV3/MouseHandler.pde new file mode 100644 index 0000000..8f0d706 --- /dev/null +++ b/B12NumbersV3/MouseHandler.pde @@ -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); + } + } + } +} diff --git a/B12NumbersV3/Number.pde b/B12NumbersV3/Number.pde new file mode 100644 index 0000000..6c28204 --- /dev/null +++ b/B12NumbersV3/Number.pde @@ -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(); +} diff --git a/B12NumbersV3/STime48.pde b/B12NumbersV3/STime48.pde new file mode 100644 index 0000000..27feb01 --- /dev/null +++ b/B12NumbersV3/STime48.pde @@ -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; + } + } + } +} diff --git a/B12NumbersV3/Stopwatch.pde b/B12NumbersV3/Stopwatch.pde index 811cb42..f9368a4 100644 --- a/B12NumbersV3/Stopwatch.pde +++ b/B12NumbersV3/Stopwatch.pde @@ -1,11 +1,14 @@ class Stopwatch{ - PVector pos; - MouseHandler mh; - STime48 time; - TimeDisplay td; - Button[] buttons; - boolean running; - color stopCol; + /* + 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); @@ -17,7 +20,12 @@ class Stopwatch{ initialize(); } - void 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)); diff --git a/B12NumbersV3/B12TimeAll.pde b/B12NumbersV3/Time48.pde similarity index 54% rename from B12NumbersV3/B12TimeAll.pde rename to B12NumbersV3/Time48.pde index 1b65a07..4c28955 100644 --- a/B12NumbersV3/B12TimeAll.pde +++ b/B12NumbersV3/Time48.pde @@ -1,4 +1,6 @@ class Time48 extends Thread{ + /* A class which stores time staticly in base 12 + */ private int sec48; private int min48; private int hour48; @@ -76,6 +78,7 @@ class Time48 extends Thread{ } // PRIVATE FUNCTIONS // + // The "flatten" functions adjust the class attributes according to whichever attribute has been updated private void flattenTSec(){ sec48 = tsec48; min48 = sec48 / 48; @@ -90,59 +93,5 @@ class Time48 extends Thread{ // 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; - } - } - } + public void run(){} // This is for STime48 to use threading } diff --git a/B12NumbersV3/TimeDisplay.pde b/B12NumbersV3/TimeDisplay.pde index dc61397..1f34a79 100644 --- a/B12NumbersV3/TimeDisplay.pde +++ b/B12NumbersV3/TimeDisplay.pde @@ -1,12 +1,15 @@ class TimeDisplay { - PVector pos; - Time48 t48; - B12Int hours; - B12Int minutes; - B12Int seconds; - B12Digit[] digits; - int tmillis; - color col; + /* + 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); @@ -60,30 +63,9 @@ class TimeDisplay { 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(); } - - // Position - /* - hours.setPos(-64, 0); - minutes.setPos(-32, 0); - seconds.setPos(0, 0); - B12Digit c1 = new B12Digit(':'); - B12Digit c2 = new B12Digit(':'); - c1.setPos(-34, 0); - c2.setPos(-66, 0); - - // Display - pushMatrix(); - translate(pos.x, pos.y); - hours.display(); - c2.display(); - minutes.display(); - c1.display(); - seconds.display(); - popMatrix();*/ } } diff --git a/B12NumbersV3/Timer.pde b/B12NumbersV3/Timer.pde index 897cb64..dfd33e9 100644 --- a/B12NumbersV3/Timer.pde +++ b/B12NumbersV3/Timer.pde @@ -1,4 +1,12 @@ 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; @@ -24,7 +32,7 @@ class Timer{ PVector getPos(){return pos;} - Timer setPos(PVector _pos){pos = _pos.copy(); return this;} + 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(){ @@ -49,7 +57,7 @@ class Timer{ } - void addChar(B12Digit digit){ + void addChar(B12Digit digit){ // Same as Clock switch(cursorPos){ case 0: td.setTime(new Time48().setHour(digit.getValue() * 12)); cursorPos += 1; break; @@ -103,11 +111,12 @@ class Timer{ }else{ setTimeButton.display(); } - if(running == true){ + 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){ + 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); diff --git a/B12NumbersV3/zchangelog.pde b/B12NumbersV3/zchangelog.pde index 832abfb..63f39c1 100644 --- a/B12NumbersV3/zchangelog.pde +++ b/B12NumbersV3/zchangelog.pde @@ -3,19 +3,40 @@ Beta version of a clock in base 12. by Nayan Sawyer started Mar 2022 - version 0.2.1.3 May 19 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 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. - // DONE finish clock applications - // TODO assemble clock application - // TODO combine clock and calcualtor into final app + // DONE put everything back into seperate tabs + // DONE fully document everything // TODO add throwing exceptions to all contructors + // 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