Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 #import('dart:html'); | |
| 6 #source('tape.dart'); | |
| 7 #source('settings.dart'); | |
| 8 #source('calcui.dart'); | |
| 9 | |
| 10 var padUI; // Calculator Pad UI. | |
|
Jacob
2012/04/05 18:06:01
can this be given a type?
| |
| 11 | |
| 12 TapeUI tapeUI; // Tape output area UI. | |
| 13 Tape tape; // Controller. | |
| 14 | |
| 15 Settings mySettings; | |
| 16 | |
| 17 String currentRegister; | |
| 18 int currentOperator; | |
| 19 double total; | |
| 20 | |
| 21 Set numberKeyPresses; | |
| 22 Set operatorKeyPresses; | |
| 23 Set equalKeyPresses; | |
| 24 Set clearKeyPresses; | |
| 25 Set dotKeyPresses; | |
| 26 Set backspacePresses; | |
| 27 | |
| 28 void setupEvents() { | |
| 29 numberKeyPresses = new Set.from([48 /* 0 */, | |
|
Jacob
2012/04/05 18:06:01
you could make this self documenting by instead of
| |
| 30 49 /* 1 */, | |
| 31 50 /* 2 */, | |
| 32 51 /* 3 */, | |
| 33 52 /* 4 */, | |
| 34 53 /* 5 */, | |
| 35 54 /* 6 */, | |
| 36 55 /* 7 */, | |
| 37 56 /* 8 */, | |
| 38 57 /* 9 */, | |
| 39 96 /* Keypad 0 */, | |
| 40 97 /* Keypad 1 */, | |
| 41 98 /* Keypad 2 */, | |
| 42 99 /* Keypad 3 */, | |
| 43 100 /* Keypad 4 */, | |
| 44 101 /* Keypad 5 */, | |
| 45 102 /* Keypad 6 */, | |
| 46 103 /* Keypad 7 */, | |
| 47 104 /* Keypad 8 */, | |
| 48 105 /* Keypad 9 */]); | |
| 49 operatorKeyPresses = new Set.from([56 /* * */, | |
| 50 187 /* + */, | |
| 51 189 /* - */, | |
| 52 191 /* / */, | |
| 53 106 /* Keypad * */, | |
| 54 107 /* Keypad + */, | |
| 55 109 /* Keypad - */, | |
| 56 111 /* Keypad / */]); | |
| 57 equalKeyPresses = new Set.from([187 /* = */, | |
| 58 13 /* ENTER */, | |
| 59 0 /* Keypad = */]); | |
| 60 clearKeyPresses = new Set.from([27 /* ESC */, | |
| 61 67 /* C */, | |
| 62 99 /* c */, | |
| 63 46 /* DEL */]); | |
| 64 dotKeyPresses = new Set.from([190 /* . */, | |
| 65 110 /* Keypad . */]); | |
| 66 backspacePresses = new Set.from([8 /* Keypad <- or Backspace */]); | |
| 67 | |
| 68 addPadEvents(); | |
| 69 | |
| 70 // Catch user keypresses, decide whether to use them or pass to the browser. | |
| 71 document.on.keyUp.add((e) { | |
| 72 processKeyEvent(e); | |
| 73 }); | |
| 74 | |
| 75 document.on.click.add((MouseEvent e) { | |
| 76 // If settings dialog is open close it. | |
| 77 mySettings.close(e); | |
| 78 | |
| 79 renderPad(document.body.elements.last()); | |
| 80 addPadEvents(); | |
| 81 }); | |
| 82 } | |
| 83 | |
| 84 void addPadEvents() { | |
| 85 // Hook-up number key events: | |
| 86 padUI.keyZero.on.click.add((MouseEvent e) { doCalc(48); }); | |
| 87 padUI.keyOne.on.click.add((MouseEvent e) { doCalc(49); }); | |
| 88 padUI.keyTwo.on.click.add((MouseEvent e) { doCalc(50); }); | |
| 89 padUI.keyThree.on.click.add((MouseEvent e) { doCalc(51); }); | |
| 90 padUI.keyFour.on.click.add((MouseEvent e) { doCalc(52); }); | |
| 91 padUI.keyFive.on.click.add((MouseEvent e) { doCalc(53); }); | |
| 92 padUI.keySix.on.click.add((MouseEvent e) { doCalc(54); }); | |
| 93 padUI.keySeven.on.click.add((MouseEvent e) { doCalc(55); }); | |
| 94 padUI.keyEight.on.click.add((MouseEvent e) { doCalc(56); }); | |
| 95 padUI.keyNine.on.click.add((MouseEvent e) { doCalc(57); }); | |
| 96 padUI.keyDot.on.click.add((MouseEvent e) { doCalc(110); }); | |
| 97 // Hook-up operator events: | |
| 98 padUI.keyPlus.on.click.add((MouseEvent e) { doCalc(107); }); | |
| 99 padUI.keyMinus.on.click.add((MouseEvent e) { doCalc(109); }); | |
| 100 padUI.keyStar.on.click.add((MouseEvent e) { doCalc(106); }); | |
| 101 padUI.keySlash.on.click.add((MouseEvent e) { doCalc(111); }); | |
| 102 padUI.keyEqual.on.click.add((MouseEvent e) { doCalc(187); }); | |
| 103 padUI.keyClear.on.click.add((MouseEvent e) { doCalc(27); }); | |
| 104 } | |
| 105 | |
| 106 void removePadEvents() { | |
| 107 // Hook-up number key events: | |
| 108 padUI.keyZero.on.click.remove((MouseEvent e) { doCalc(48); }); | |
|
Jacob
2012/04/05 18:06:01
this won't remove the event listeners attached abo
| |
| 109 padUI.keyOne.on.click.remove((MouseEvent e) { doCalc(49); }); | |
| 110 padUI.keyTwo.on.click.remove((MouseEvent e) { doCalc(50); }); | |
| 111 padUI.keyThree.on.click.remove((MouseEvent e) { doCalc(51); }); | |
| 112 padUI.keyFour.on.click.remove((MouseEvent e) { doCalc(52); }); | |
| 113 padUI.keyFive.on.click.remove((MouseEvent e) { doCalc(53); }); | |
| 114 padUI.keySix.on.click.remove((MouseEvent e) { doCalc(54); }); | |
| 115 padUI.keySeven.on.click.remove((MouseEvent e) { doCalc(55); }); | |
| 116 padUI.keyEight.on.click.remove((MouseEvent e) { doCalc(56); }); | |
| 117 padUI.keyNine.on.click.remove((MouseEvent e) { doCalc(57); }); | |
| 118 padUI.keyDot.on.click.remove((MouseEvent e) { doCalc(110); }); | |
| 119 // Hook-up operator events: | |
| 120 padUI.keyPlus.on.click.remove((MouseEvent e) { doCalc(107); }); | |
| 121 padUI.keyMinus.on.click.remove((MouseEvent e) { doCalc(109); }); | |
| 122 padUI.keyStar.on.click.remove((MouseEvent e) { doCalc(106); }); | |
| 123 padUI.keySlash.on.click.remove((MouseEvent e) { doCalc(111); }); | |
| 124 padUI.keyEqual.on.click.remove((MouseEvent e) { doCalc(187); }); | |
| 125 padUI.keyClear.on.click.remove((MouseEvent e) { doCalc(27); }); | |
| 126 } | |
| 127 | |
| 128 void renderPad(Element parentElement) { | |
| 129 bool update = false; | |
| 130 | |
| 131 if (mySettings.isSimple && !(padUI is FlatPadUI)) { | |
| 132 if (padUI != null) { | |
| 133 removePadEvents(); | |
| 134 } | |
| 135 padUI = new FlatPadUI(); | |
| 136 update = true; | |
| 137 } else if (mySettings.isButton && !(padUI is ButtonPadUI)) { | |
| 138 if (padUI != null) { | |
| 139 removePadEvents(); | |
| 140 } | |
| 141 padUI = new ButtonPadUI(); | |
| 142 update = true; | |
| 143 } | |
| 144 | |
| 145 if (update) { | |
| 146 // Update calculator pad. | |
| 147 | |
| 148 // Remove previous pad UI | |
| 149 if (parentElement.elements.length > 1) { | |
| 150 parentElement.elements.last().remove(); | |
| 151 } | |
| 152 | |
| 153 // Add new pad UI. | |
| 154 parentElement.elements.add(padUI.root); | |
| 155 } | |
| 156 } | |
| 157 | |
| 158 /** | |
| 159 * Controls the logic of how to respond to keypresses and then update the | |
| 160 * UI accordingly. | |
| 161 */ | |
| 162 void processKeyEvent(KeyboardEvent e) { | |
| 163 int code = e.keyCode; | |
| 164 bool shift = e.shiftKey; | |
| 165 bool ctrl = e.ctrlKey; | |
| 166 | |
| 167 doCalc(code, shift, ctrl); | |
| 168 } | |
| 169 | |
| 170 void doCalc(int code, [bool shift = false, bool ctrl = false]) { | |
| 171 // If settings dialog is open close it. | |
| 172 mySettings.close(); | |
| 173 | |
| 174 if (numberKeyPresses.contains(code)) { | |
| 175 if (code == 56 && shift) { | |
| 176 /* * operator */ | |
| 177 processOperator(padUI.keyStar); | |
| 178 return; | |
| 179 } else if (code >= 96) { | |
| 180 code -= 48; // Normalize from keypad code to ASCII code. | |
| 181 } | |
| 182 | |
| 183 Element element; | |
| 184 switch (code) { | |
| 185 case 48: | |
| 186 element = padUI.keyZero; | |
| 187 break; | |
| 188 case 49: | |
| 189 element = padUI.keyOne; | |
| 190 break; | |
| 191 case 50: | |
| 192 element = padUI.keyTwo; | |
| 193 break; | |
| 194 case 51: | |
| 195 element = padUI.keyThree; | |
| 196 break; | |
| 197 case 52: | |
| 198 element = padUI.keyFour; | |
| 199 break; | |
| 200 case 53: | |
| 201 element = padUI.keyFive; | |
| 202 break; | |
| 203 case 54: | |
| 204 element = padUI.keySix; | |
| 205 break; | |
| 206 case 55: | |
| 207 element = padUI.keySeven; | |
| 208 break; | |
| 209 case 56: | |
| 210 element = padUI.keyEight; | |
| 211 break; | |
| 212 case 57: | |
| 213 element = padUI.keyNine; | |
| 214 break; | |
| 215 default: | |
| 216 tape.displayError("Unknown key"); | |
| 217 } | |
| 218 processNumber(code, element); | |
| 219 } else if (operatorKeyPresses.contains(code)) { | |
| 220 int op; | |
| 221 | |
| 222 if ((shift && code == 56) || code == 106) { | |
| 223 /* * operator */ | |
| 224 processOperator(padUI.keyStar); | |
| 225 } else if ((shift && code == 187) || code == 107) { | |
| 226 /* + operator */ | |
| 227 processOperator(padUI.keyPlus); | |
| 228 } else if ((code == 189 && !shift) || code == 109) { | |
| 229 /* - operator */ | |
| 230 processOperator(padUI.keyMinus); | |
| 231 } else if ((code == 191 && !shift) || code == 111) { | |
| 232 /* / operator */ | |
| 233 processOperator(padUI.keySlash); | |
| 234 } else if (!shift && code == 187) { | |
| 235 // Equal operator. | |
| 236 processOperator(padUI.keyEqual); | |
| 237 } else { | |
| 238 // No match. | |
| 239 return; | |
| 240 } | |
| 241 } else if (clearKeyPresses.contains(code)) { | |
| 242 resetCalculatorState(); | |
| 243 } else if (dotKeyPresses.contains(code) && !shift) { | |
| 244 processNumber(46, padUI.keyDot); | |
| 245 } else if (equalKeyPresses.contains(code) && !shift) { | |
| 246 processOperator(padUI.keyClear); | |
| 247 } else if (backspacePresses.contains(code)) { | |
| 248 if (ctrl) { | |
| 249 // CTRL + BS or CTRL + DEL works like C, c, ESC, DEL and removes all | |
| 250 // entries in the tape. | |
| 251 resetCalculatorState(); | |
| 252 tape.clearTape(); | |
| 253 } else { | |
| 254 currentRegister = currentRegister.substring(0, | |
| 255 Math.max(0, currentRegister.length - 1)); | |
| 256 tape.addToTape(Tape.OP_NOOP, currentRegister); | |
| 257 } | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 void processNumber(int code, Element key) { | |
| 262 String char = new String.fromCharCodes([code]); | |
| 263 | |
| 264 // TODO(terry): Need to fix this in Dart library. | |
| 265 // If there's already a . in our current register don't allow a second period. | |
| 266 // Math.parseDouble validates that 2.2.3.4.5 is okay and returns 2.2 | |
| 267 if (char == '.' && currentRegister.indexOf('.') != -1) { | |
| 268 // Signal dot is valid more than once for a number. | |
| 269 flickerKey(padUI.keyDot, '-error'); | |
| 270 return; | |
| 271 } else { | |
| 272 currentRegister = "${currentRegister}${char}"; | |
| 273 } | |
| 274 | |
| 275 flickerKey(key); | |
| 276 tape.addToTape(Tape.OP_NOOP, currentRegister); | |
| 277 } | |
| 278 | |
| 279 void processOperator(var element) { | |
| 280 flickerKey(element); | |
| 281 | |
| 282 if (currentRegister.length != 0) { | |
| 283 int op; | |
| 284 | |
| 285 if (element == padUI.keyPlus) { | |
| 286 op = Tape.OP_PLUS; | |
| 287 } else if (element == padUI.keyMinus) { | |
| 288 if (currentRegister == "-") { | |
| 289 currentRegister = ""; | |
| 290 op = Tape.OP_NOOP; | |
| 291 } else if (currentRegister == "-.") { | |
| 292 currentRegister = "."; | |
| 293 op = Tape.OP_NOOP; | |
| 294 } else { | |
| 295 op = Tape.OP_MINUS; | |
| 296 } | |
| 297 } else if (element == padUI.keyStar) { | |
| 298 op = Tape.OP_MULTI; | |
| 299 } else if (element == padUI.keySlash) { | |
| 300 op = Tape.OP_DIV; | |
| 301 } else if (element == padUI.keyEqual) { | |
| 302 op = Tape.OP_EQUAL; | |
| 303 } else if (element == padUI.keyClear) { | |
| 304 op = Tape.OP_CLEAR; | |
| 305 } else { | |
| 306 tape.displayError("Unknown operator"); | |
| 307 } | |
| 308 | |
| 309 // If operator has no current number then don't display another operator | |
| 310 // until operand is entered. | |
| 311 if (currentRegister.length != 0 || | |
| 312 (tape.activeTotal == null && op == Tape.OP_EQUAL)) { | |
| 313 tape.addToTape(op, currentRegister); | |
| 314 } | |
| 315 | |
| 316 currentRegister = ""; | |
| 317 } else if (element == padUI.keyMinus) { | |
| 318 currentRegister = "-"; | |
| 319 tape.addToTape(Tape.OP_NOOP, currentRegister); | |
| 320 } | |
| 321 } | |
| 322 | |
| 323 void resetCalculatorState() { | |
| 324 flickerKey(padUI.keyClear); | |
| 325 tape.removeActiveElements(); | |
| 326 if (!tape.isClear) { | |
| 327 tape.clearTotal(); | |
| 328 currentRegister = ""; | |
| 329 currentOperator = null; | |
| 330 total = 0.0; | |
| 331 } | |
| 332 } | |
| 333 | |
| 334 void flickerKey(Element key, [String postfix = '-hover']) { | |
| 335 // Only Change classes with 1 hyphen that's the main class for an element | |
| 336 // to handle hover and active. | |
| 337 String theClass; | |
| 338 for (final String cls in key.classes) { | |
|
Jacob
2012/04/05 18:06:01
Looping through all css class names should be avoi
| |
| 339 if (cls.split('-').length == 2) { | |
| 340 theClass = cls; | |
| 341 } | |
| 342 } | |
| 343 key.classes.add('${theClass}${postfix}'); | |
| 344 final String nextPostfix = (postfix == '-error') ? '-error' : '-press'; | |
| 345 window.setTimeout(() => resetKey(key, '${theClass}${postfix}', | |
| 346 '${theClass}${nextPostfix}'), 80); | |
| 347 } | |
| 348 | |
| 349 void resetKey(Element key, String classToRemove, [String classToAdd = ""]) { | |
| 350 if (key != null) { | |
| 351 key.classes.remove(classToRemove); | |
| 352 if (classToAdd.length > 0) { | |
| 353 key.classes.add(classToAdd); | |
| 354 window.setTimeout(() => resetKey(key, classToAdd), 80); | |
|
Jacob
2012/04/05 18:06:01
make 80 a constant
| |
| 355 } | |
| 356 } | |
| 357 } | |
| 358 | |
| 359 void main() { | |
| 360 final Element element = new Element.tag('div'); | |
|
Jacob
2012/04/05 18:06:01
nit:
final Element element ==> final element;
Als
| |
| 361 | |
| 362 // Create our Tape UI. | |
| 363 tapeUI = new TapeUI(); | |
| 364 element.elements.add(tapeUI.root); | |
| 365 | |
| 366 // Create our tape controller. | |
| 367 tape = new Tape(); | |
| 368 | |
| 369 renderPad(element); | |
| 370 | |
| 371 // Render the UI. | |
| 372 document.body.elements.add(element); | |
| 373 | |
| 374 currentRegister = ""; | |
| 375 total = 0.0; | |
| 376 | |
| 377 setupEvents(); | |
| 378 } | |
| OLD | NEW |