Home | Trees | Indices | Help |
---|
|
1 #!/usr/bin/env python 2 3 # TODO: 4 # - Fast visit interpreted as flick 5 # - Widen word list scroll bar 6 # - Button to copy output to clipboard 7 # - Make cnt-c work 8 # - Hook up with text-to-speech 9 # - Help panel 10 # - Revise UI to get buttons close together. 11 12 13 import sys; 14 import os; 15 sys.path.append(os.path.join(os.path.dirname(__file__), "../../lib")); 16 from ternarytree import TernarySearchTree; 17 18 import re; 19 from functools import partial; 20 21 from utilities import Utilities; 22 23 from gesture_buttons.gesture_button import GestureButton; 24 from gesture_buttons.gesture_button import FlickDirection; 25 26 from qt_comm_channel.commChannel import CommChannel; 27 28 from word_completion.word_collection import TelPadEncodedWordCollection; 29 30 import python_qt_binding 31 from python_qt_binding import QtCore, QtGui, loadUi 32 from QtCore import QMutex, QMutexLocker, Qt, QTimer, QRect, Slot 33 from QtGui import QApplication, QColor, QDialog, QMainWindow, QMessageBox, QPixmap, QWidget, QIcon 34 from QtGui import QButtonGroup 35 36 WORD_LIST_SCROLLBAR_WIDTH = 30; # pixels 37 38 39 NUM_LETTER_BUTTONS = 8;42 ''' 43 Mapping from loose word frequency usage terminology 44 to concrete frequency rank. A word's frequency being 45 ranked with the number r means that this word is used 46 as frequently the the rth most frequently used word 47 in out dictionary. 48 ''' 49 RARELY = 4000; 50 OCCASIONALLY = 100; 51 CONSTANTLY = 0;52 5658 ''' 59 Enum: Identifies whether a style is for a depressed, or released button. 60 ''' 61 RELEASED = 0; 62 PRESSED = 1;6365 ''' 66 Enum: input came from gesturing vs. explicit letter input. 67 ''' 68 DIALPAD = 0; 69 LETTER_INPUT = 1;7072 ''' 73 Enum used to identify gesture buttons. 74 ''' 75 ABC = 0; 76 DEF = 1; 77 GHI = 2; 78 JKL = 3; 79 MNO = 4; 80 PQR = 5; 81 STUV = 6; 82 WXYZ = 7; 83 84 legalValues = range(8); 85 strRepr = {ABC:'ABC', 86 DEF:'DEF', 87 GHI:'GHI', 88 JKL:'JKL', 89 MNO:'MNO', 90 PQR:'PQR', 91 STUV:'STUV', 92 WXYZ:'WXYZ'}; 93 94 strToID = {'ABC' : ABC, 95 'DEF' : DEF, 96 'GHI' : GHI, 97 'JKL' : JKL, 98 'MNO' : MNO, 99 'PQR' : PQR, 100 'STUV': STUV, 101 'WXYZ': WXYZ}; 102 103 idRepr = {ABC:'|abc|', 104 DEF:'|def|', 105 GHI:'|ghi|', 106 JKL:'|jkl|', 107 MNO:'|mno|', 108 PQR:'|pqr|', 109 STUV:'|stuv|', 110 WXYZ:'|wxyz|'}; 111 112 @staticmethod145114 ''' 115 Returns displayable description of the button. 116 @param buttonID: a key in the C{idRepr} dict 117 @type buttonID: {ABC|DEF|JKL|MNO|PQR|STUV|WXYZ} 118 ''' 119 try: 120 return ButtonID.strRepr[buttonID]; 121 except KeyError: 122 raise ValueError("Unknown button ID '%s'." % buttonID);123 124 @staticmethod126 ''' 127 Given a button label, return the button's ID 128 @param buttonLabel: label that is printed on the button 129 @type buttonLabel: string 130 ''' 131 return ButtonID.strToID[buttonLabel];132 133 @staticmethod135 ''' 136 Return a string representing the meaning of a button. 137 @param buttonID: a key in the C{idRepr} dict 138 @type buttonID: {ABC|DEF|JKL|MNO|PQR|STUV|WXYZ} 139 @raise ValueError: if button ID not recognized. 140 ''' 141 try: 142 return ButtonID.idRepr[buttonID]; 143 except KeyError: 144 raise ValueError("Unknown button ID '%s'." % buttonID);147 148 # Ids for checkboxes in the 'add-new-word' dialog: 149 RARELY_BUTTON_ID = 0; 150 OCCCASIONALLY_BUTTON_ID = 1; 151 CONSTANTLY_BUTTON_ID = 2; 152764 765 if __name__ == "__main__": 766 767 app = QApplication(sys.argv); 768 b = TBoard(); 769 app.exec_(); 770 sys.exit(); 771154 super(TBoard, self).__init__(); 155 156 self.setWindowTitle("TBoard"); 157 158 # Find QtCreator's XML file in the PYTHONPATH: 159 currDir = os.path.realpath(__file__); 160 relPathQtCreatorFile = "tboard_ui/tboard_ui.ui"; 161 qtCreatorXMLFilePath = Utilities.findFile(relPathQtCreatorFile); 162 if qtCreatorXMLFilePath is None: 163 raise ValueError("Can't find QtCreator user interface file %s" % relPathQtCreatorFile); 164 # Make QtCreator generated UI a child if this instance: 165 python_qt_binding.loadUi(qtCreatorXMLFilePath, self); 166 self.letterWidgets = [self.ABCWidget, self.DEFWidget, self.GHIWidget, self.JKLWidget, 167 self.MNOWidget, self.PQRWidget, self.STUVWidget, self.WXYZWidget]; 168 169 self.createColors(); 170 171 # Populate all empty letter board button widgets with 172 # GestureButton instances: 173 self.populateGestureButtons(); 174 175 self.preparePixmaps(); 176 177 # Increase the width of the word area scrollbar: 178 self.wordList.verticalScrollBar().setFixedWidth(WORD_LIST_SCROLLBAR_WIDTH) # pixels 179 180 # Where we accumulate evolving words in encoded form 181 # (see symbolToEnc dict in word_collection.py): 182 self.encEvolvingWord = ""; 183 self.currButtonUsedForFlick = False; 184 self.wordCollection = TelPadEncodedWordCollection(); 185 186 # Timer to ensure that a crossed-out button doesn't 187 # stay crossed out forever: 188 self.crossOutTimer = QTimer(); 189 self.crossOutTimer.setSingleShot(True); 190 self.crossedOutButtons = []; 191 192 # Popup dialog for adding new words to dictionary: 193 self.initNewDictWordDialog(); 194 195 # Gesture buttons all in Dialpad (speed-write mode): 196 self.buttonEditMode = ButtonEditMode.DIALPAD; 197 198 # Disable selecting for the remaining-words panel: 199 self.wordList.setFocusPolicy(Qt.NoFocus); 200 201 # Mutex for keeping very fast flicking gestures 202 # out of each others' hair: 203 self.mutex = QMutex(); 204 205 # The system clipboard for copy: 206 self.clipboard = QApplication.clipboard(); 207 208 # Speak-button not working yet: 209 self.speakButton.setDisabled(True); 210 211 self.connectWidgets(); 212 #self.setGeometry(500, 500, 300, 100); 213 self.show();214 215 216 # -------------------------------------- UI Setup Methods ------------------------- 217219 ''' 220 Initializes dialog window for user to add a new word to the dictionary. 221 ''' 222 223 # Find QtCreator's XML file in the PYTHONPATH: 224 currDir = os.path.realpath(__file__); 225 relPathQtCreatorFile = "tboard_ui/addWord_dialog/addWordDialog.ui"; 226 qtCreatorXMLFilePath = Utilities.findFile(relPathQtCreatorFile); 227 if qtCreatorXMLFilePath is None: 228 raise ValueError("Can't find QtCreator user interface file for 'new dictionary word' dialog file %s" % relPathQtCreatorFile); 229 #****self.addWordDialog = QWidget(); 230 self.addWordDialog = QDialog(); 231 python_qt_binding.loadUi(qtCreatorXMLFilePath, self.addWordDialog); 232 # Assign int IDs to the frequency checkboxes: 233 rareButton = self.addWordDialog.useRarelyButton; 234 occasionButton = self.addWordDialog.useOccasionallyButton; 235 constantButton = self.addWordDialog.useConstantlyButton; 236 self.addWordButtonGroup = QButtonGroup(); 237 self.addWordButtonGroup.addButton(rareButton, TBoard.RARELY_BUTTON_ID); 238 self.addWordButtonGroup.addButton(occasionButton, TBoard.OCCCASIONALLY_BUTTON_ID); 239 self.addWordButtonGroup.addButton(constantButton, TBoard.CONSTANTLY_BUTTON_ID); 240 self.addWordDialog.hide();241243 ''' 244 Creates GestureButton instances for each telephone pad button. 245 Creates convenience data structures: 246 - C{letterButtons} is an array of all GestureButton instances 247 - C{letterButtonToID} maps GestureButton instances to the buttons' 248 IDs, which happen to be their label strings ('ABC', 'DEF', etc.). 249 - C{idToLetterButton} is the reverse: a dictionary mapping button labels, 250 like "ABC" to the corresponding button instance. 251 This function also sets style sheets for the all GestureButton instances. 252 ''' 253 # Sorted array of all letter button objs: 254 self.letterButtons = []; 255 # Letter button object to button label: "ABC", "DEF", etc: 256 self.letterButtonToID = {}; 257 self.idToLetterButton = {}; 258 for buttonID in ButtonID.legalValues: 259 self.letterButtons.append(GestureButton(ButtonID.toString(buttonID), 260 parent=self.letterWidgets[buttonID])); 261 self.letterButtonToID[self.letterButtons[-1]] = self.letterButtons[-1].text(); 262 self.letterButtons[-1].setGeometry(0,0,200,100); 263 self.idToLetterButton[self.letterButtons[-1].text()] = self.letterButtons[-1]; 264 for buttonObj in self.letterButtons: 265 self.setGestureButtonStyle(buttonObj, StyleID.RELEASED); 266 #****buttonObj.setFocusPolicy(Qt.FocusPolicy.NoFocus); 267 buttonObj.setFocusPolicy(Qt.NoFocus);268 269271 ''' 272 Connect signals and button slots to their handlers. 273 ''' 274 CommChannel.getSignal('GestureSignals.flickSig').connect(self.handleButtonFlicks); 275 CommChannel.getSignal('GestureSignals.buttonEnteredSig').connect(self.handleButtonEntered); 276 CommChannel.getSignal('GestureSignals.buttonExitedSig').connect(self.handleButtonExited); 277 self.eraseWordButton.clicked.connect(self.handleEraseWordButton); 278 self.addWordButton.clicked.connect(self.handleSaveWordButton); 279 self.crossOutTimer.timeout.connect(self.handleCrossoutTimeout); 280 # Number pad: 281 for button in set([self.numPad1, self.numPad2, self.numPad3, self.numPad4, self.numPad5, 282 self.numPad6, self.numPad7, self.numPad8, self.numPad9, self.numPad0]): 283 button.clicked.connect(partial(self.handleNumPad, button)); 284 285 # Special characters: 286 for button in set([self.commaButton, self.colonButton, self.questionButton, self.atButton, self.leftParenButton, 287 self.periodButton, self.backspaceButton, self.slashButton, self.spaceButton, self.rightParenButton]): 288 button.clicked.connect(partial(self.handleSpecialChars, button)); 289 290 # Gesture button clicks (switching between dialpad and letter mode: 291 for buttonObj in self.letterButtons: 292 buttonObj.clicked.connect(partial(self.handleGestureButtonClick, buttonObj)); 293 294 # Add word dialog box capitalization checkbox state changed: 295 self.addWordDialog.capitalizeCheckbox.stateChanged.connect(self.handleAddDictWordCapitalizeStateChanged); 296 # Add word dialog box OK or Cancel botton clicked: 297 self.addWordDialog.cancelButton.clicked.connect(partial(self.handleAddDictWordOK_Cancel, self.addWordDialog.cancelButton)); 298 self.addWordDialog.addWordButton.clicked.connect(partial(self.handleAddDictWordOK_Cancel, self.addWordDialog.addWordButton)); 299 300 # CopyAll button: 301 self.copyButton.clicked.connect(self.handleCopyAll);302304 ''' 305 Pull icons from the file system, and turn them into pixmaps. 306 ''' 307 308 imgDirPath = os.path.join(os.path.dirname(__file__), "img/"); 309 self.buttonBackGroundPixmaps = []; 310 buttonWidth = self.letterButtons[0].width(); 311 buttonHeight = self.letterButtons[0].height(); 312 for backgroundImgNum in range(NUM_LETTER_BUTTONS): 313 buttonPixmap = QPixmap(); 314 #****imgPath = os.path.join(imgDirPath, "tboardButtonBackgroundTrail" + str(backgroundImgNum + 1) + ".png"); 315 imgPath = os.path.join(imgDirPath, "tboardButtonBackgroundsSmall" + str(backgroundImgNum + 1) + ".png"); 316 if not buttonPixmap.load(imgPath): 317 raise IOError("Could not find button background icon at " + imgPath); 318 #scaledPixmap = buttonPixmap.scaled(buttonWidth, buttonHeight); 319 #*****scaledPixmap = buttonPixmap.scaled(buttonWidth + 50, buttonHeight); 320 scaledPixmap = buttonPixmap; 321 #***** 322 self.buttonBackGroundPixmaps.append(scaledPixmap); 323 324 self.crossedOutButtonBackground = QPixmap(); 325 imgPath = os.path.join(imgDirPath, "tboardButtonBackgroundCrossedOut.png"); 326 if not self.crossedOutButtonBackground.load(imgPath): 327 raise IOError("Could not find crossed-out button background icon at " + imgPath); 328 self.crossedOutButtonBackground = self.crossedOutButtonBackground.scaled(buttonWidth + 50, buttonHeight); 329 330 # Initialize all buttons to a background with 331 # trail spot 8 (darkest): 332 for button in self.letterButtons: 333 self.setButtonImage(button, self.buttonBackGroundPixmaps[NUM_LETTER_BUTTONS - 1]); 334 335 # Initialize dictionary that tracks button background icons. 336 # Keys are button objs, values are ints that index into the 337 # self.buttonBackgroundPixmaps array. None means the button 338 # is so old that it has a plain background, or that it was never 339 # used so far: 340 self.currentButtonBackgrounds = {}; 341 for buttonObj in self.letterButtons: 342 self.currentButtonBackgrounds[buttonObj] = None; 343 344 self.setStyleSheet("QWidget{background-color: %s}" % self.offWhiteColor.name());345347 ''' 348 Create QColor objects from RGB values. 349 ''' 350 self.grayBlueColor = QColor(89,120,137); # Letter buttons 351 self.offWhiteColor = QColor(206,230,243); # Background 352 self.darkGray = QColor(65,88,101); # Central buttons 353 self.wordListFontColor = QColor(62,143,185); # Darkish blue. 354 self.purple = QColor(147,124,195); # Gesture button pressed355357 ''' 358 Style a gesture button. 359 @param buttonObj: the button to style 360 @type buttonObj: GestureButton 361 @param styleID: whether button is pressed or released 362 @type styleID: StyleID 363 ''' 364 if styleID == StyleID.RELEASED: 365 buttonObj.setStyleSheet("background-color: %s; color: %s; border: 2px outset %s; border-radius: 15; font-size: 18px" % 366 (self.grayBlueColor.name(), 367 self.offWhiteColor.name(), 368 self.offWhiteColor.name())); 369 370 elif styleID == StyleID.PRESSED: 371 buttonObj.setStyleSheet("background-color: %s; color: %s; border-radius: 15; font-size: 22px" % 372 (self.purple.name(), 373 self.offWhiteColor.name())); 374 self.setFocus();375 376 # -------------------------------------- Signal Handlers ------------------------- 377 378 @Slot(GestureButton, int)380 ''' 381 Action on flicking in and out of a gesture button. 382 @param gestureButton: button that was flicked 383 @type gestureButton: GestureButton 384 @param flickDirection: cursor flicked North, South, East, or West 385 @type flickDirection: GestureButton.FlickDirection 386 ''' 387 #print "Flick direction: " + FlickDirection.toString(flickDirection); 388 389 # Protect against re-entry. Not that 390 # QtCore.QMutexLocker locks when created, and 391 # unlocks when destroyed (i.e. when function 392 # is left; no explicit unlocking needed); 393 394 myMutexLocker = QMutexLocker(self.mutex); 395 396 # West flick: Undo last letter (in Dialpad mode) or 397 # highlight next letter (in Letter_Edit mod): 398 if flickDirection == FlickDirection.WEST: 399 if self.buttonEditMode == ButtonEditMode.DIALPAD: 400 self.erasePreviousLetter(); 401 self.showRemainingWords(); 402 self.updateTickerTape(); 403 else: # individual-letter-input mode: 404 self.highlightNextLetter(gestureButton, FlickDirection.WEST); 405 406 # North flick: Scroll word list up: 407 elif flickDirection == FlickDirection.NORTH: 408 currRemainingWordsRow = self.wordList.currentRow(); 409 if currRemainingWordsRow == 0 or self.buttonEditMode == ButtonEditMode.LETTER_INPUT: 410 pass; 411 else: 412 self.wordList.setCurrentRow(currRemainingWordsRow - 1); 413 # South flick: Scroll word list down: 414 elif flickDirection == FlickDirection.SOUTH: 415 currRemainingWordsRow = self.wordList.currentRow(); 416 if currRemainingWordsRow >= self.wordList.count() or self.buttonEditMode == ButtonEditMode.LETTER_INPUT: 417 pass; 418 else: 419 self.wordList.setCurrentRow(currRemainingWordsRow + 1); 420 # East flick: Accept word that is selected in remaining words list: 421 else: 422 if self.buttonEditMode == ButtonEditMode.LETTER_INPUT: 423 self.highlightNextLetter(gestureButton, FlickDirection.EAST); 424 else: 425 # No word in word list? 426 count = self.wordList.count() 427 currItem = self.wordList.currentItem(); 428 if count <= 0 or currItem is None: 429 pass; 430 else: 431 self.outputPanel.insertPlainText(" " + currItem.text()); 432 # Word entry done for this word: 433 self.eraseCurrentWord(); 434 435 # Remember that we just used this button 436 # for a flick action. 437 self.currButtonUsedForFlick = True;438 439 @Slot(GestureButton) 443 444 @Slot(GestureButton)446 ''' 447 Handler for cursor having entered a gesture button. 448 @param gestureButtonObj: button object that was entered 449 @type gestureButtonObj: GestureButton 450 ''' 451 452 # Protect against re-entry. Not that 453 # QtCore.QMutexLocker locks when created, and 454 # unlocks when destroyed (i.e. when function 455 # is left; no explicit unlocking needed); 456 457 myMutexLocker = QMutexLocker(self.mutex); 458 459 # If we are in letter entry mode, return this button 460 # to Dialpad mode: 461 if self.buttonEditMode == ButtonEditMode.LETTER_INPUT: 462 self.switchButtonMode(gestureButtonObj, ButtonEditMode.DIALPAD); 463 return; 464 465 # If button being left was just used for a flick, 466 # don't count the exit: 467 if self.currButtonUsedForFlick: 468 self.currButtonUsedForFlick = False; 469 return; 470 471 # Get 'ABC', or 'DEF', etc representation from the button: 472 buttonLabelAsStr = str(gestureButtonObj); 473 newEncLetter = self.wordCollection.encodeTelPadLabel(buttonLabelAsStr); 474 self.encEvolvingWord += newEncLetter; 475 self.shiftButtonTrails(HistoryShiftDir.OLDER, newHead=gestureButtonObj); 476 #print self.encEvolvingWord; 477 self.showRemainingWords(); 478 self.updateTickerTape();479481 ''' 482 Handler for erase-word button clicked. 483 ''' 484 self.eraseCurrentWord(); 485 self.showRemainingWords(); 486 self.updateTickerTape();487489 ''' 490 Timeout handler that detects crossing out a letter by running through a gesture button and back. 491 ''' 492 for buttonObj in self.crossedOutButtons: 493 self.setButtonImage(buttonObj, self.buttonBackGroundPixmaps[self.currentButtonBackgrounds[buttonObj]]); 494 self.crossedOutButtons = [];495497 ''' 498 Handler for number pad button pressed. 499 @param numButton: button object 500 @type numButton: QPushButton 501 ''' 502 buttonLabel = numButton.text(); 503 self.outputPanel.insertPlainText(buttonLabel);504506 ''' 507 Handler: special character button pushed. 508 @param specCharButton: button object 509 @type specCharButton: QPushButton 510 ''' 511 if specCharButton == self.backspaceButton: 512 self.outputPanel.textCursor().deletePreviousChar(); 513 return; 514 elif specCharButton == self.spaceButton: 515 char = " "; 516 else: 517 char = specCharButton.text(); 518 self.outputPanel.insertPlainText(char);519521 ''' 522 Handler for gesture button click. 523 @param buttonObj: Button object 524 @type buttonObj: GestureButton 525 ''' 526 527 # If button is in default dialpad mode, switch to letter-input mode: 528 if self.buttonEditMode == ButtonEditMode.DIALPAD: 529 self.switchButtonMode(buttonObj, ButtonEditMode.LETTER_INPUT); 530 531 # If button is in letter edit mode, add the currently 532 # capitalized letter to the output panel, and switch the 533 # button back into default dialpad mode: 534 elif self.buttonEditMode == ButtonEditMode.LETTER_INPUT: 535 labelBeingEdited = buttonObj.text(); 536 capLetter = labelBeingEdited[self.findCapitalLetter(labelBeingEdited)]; 537 self.outputPanel.insertPlainText(capLetter.lower()); 538 self.switchButtonMode(buttonObj, ButtonEditMode.DIALPAD);539541 # Get content of output panel: 542 currOutput = self.outputPanel.toPlainText(); 543 # If noth'n there, done: 544 if len(currOutput) == 0: 545 QMessageBox.information(self, "Dictionary addition", "Output panel has no content; so there is no word to save.", QMessageBox.Ok, QMessageBox.NoButton); 546 return; 547 # Get the last word in the output panel: 548 newWord = re.split("[.;:?! @()]", currOutput)[-1]; 549 # Ask user about capitalization, and expected word frequency. 550 # This call will raise a modal dialog box. Signal handlers 551 # handleAddDictWordCapitalizeStateChanged(), and handleAddDictWordOK_Cancel() 552 # take it from there: 553 self.getAddWordUserInfo(newWord);554556 dialog = self.addWordDialog; 557 newWord = dialog.newWord.text(); 558 if newCapsState == 0: 559 dialog.newWord.setText(newWord.lower()); 560 else: 561 dialog.newWord.setText(newWord.capitalize());562564 if button == self.addWordDialog.cancelButton: 565 self.addWordDialog.hide(); 566 return; 567 568 frequencyCheckboxID = self.addWordButtonGroup.checkedId(); 569 if frequencyCheckboxID == TBoard.RARELY_BUTTON_ID: 570 freqRank = UseFrequency.RARELY; 571 elif frequencyCheckboxID == TBoard.OCCCASIONALLY_BUTTON_ID: 572 freqRank = UseFrequency.OCCASIONALLY; 573 elif frequencyCheckboxID == TBoard.CONSTANTLY_BUTTON_ID: 574 freqRank = UseFrequency.CONSTANTLY; 575 else: 576 raise ValueError("Unknown use frequency checkbox ID in add word to dictionary dialog handling: " + str(frequencyCheckboxID)); 577 578 self.doAddWordButton(self.addWordDialog.newWord.text(), freqRank); 579 self.addWordDialog.hide();580 583 584 # -------------------------------------- UI Manipulation ------------------------- 585587 additionResult = self.wordCollection.addToUserDict(newWord, rankInt=rank); 588 if additionResult: 589 QMessageBox.information(self, # dialog parent 590 "Dictionary addition", "Word '%s' has been saved in user dictionary." % newWord, 591 QMessageBox.Ok, 592 QMessageBox.NoButton); 593 else: 594 QMessageBox.information(self, # dialog parent 595 "Dictionary addition", "Word '%s' was already in the dictionary. No action taken" % newWord, 596 QMessageBox.Ok, 597 QMessageBox.NoButton);598 599601 if newEditMode == ButtonEditMode.DIALPAD: 602 self.setGestureButtonStyle(buttonObj, StyleID.RELEASED); 603 self.buttonEditMode = ButtonEditMode.DIALPAD; 604 buttonObj.setText(buttonObj.text().upper()); 605 elif newEditMode == ButtonEditMode.LETTER_INPUT: 606 self.setGestureButtonStyle(buttonObj, StyleID.PRESSED); 607 self.buttonEditMode = ButtonEditMode.LETTER_INPUT; 608 buttonObj.setText(buttonObj.text().capitalize());609611 label = buttonObj.text(); 612 capitalLetterPos = self.findCapitalLetter(label); 613 label = label.lower(); 614 if flickDirection == FlickDirection.EAST: 615 newCapPos = (capitalLetterPos + 1) % len(label); 616 else: 617 newCapPos = (capitalLetterPos - 1) % len(label); 618 #label = label[:newCapPos] + label[newCapPos].upper() + label[min(newCapPos + 1, len(label) - 1):]; 619 label = label[:newCapPos] + label[newCapPos].upper() + label[newCapPos + 1:] if newCapPos < len(label) else ""; 620 621 buttonObj.setText(label);622624 for (pos, char) in enumerate(word): 625 if char.isupper(): 626 return pos; 627 raise ValueError("No capital letter found.");628 629631 if len(self.encEvolvingWord) == 0: 632 self.tickerTape.setText(""); 633 return; 634 visibleEncoding = ""; 635 for encChar in self.encEvolvingWord: 636 dialpadButtonLabel = self.wordCollection.decodeTelPadLabel(encChar); 637 buttonID = ButtonID.toButtonID(dialpadButtonLabel); 638 visibleEncoding += ButtonID.idToStringable(buttonID); 639 self.tickerTape.setText(visibleEncoding);640642 remainingWords = self.wordCollection.prefix_search(self.encEvolvingWord); 643 rankSortedWords = sorted(remainingWords, key=self.wordCollection.rank); 644 self.wordList.clear(); 645 646 self.wordList.addItems(rankSortedWords); 647 self.wordList.setCurrentRow(0);648 649 #print self.wordCollection.prefix_search(self.encEvolvingWord); 650652 self.encEvolvingWord = ""; 653 self.updateTickerTape(); 654 self.eraseTrail(); 655 self.wordList.clear();656658 if len(self.encEvolvingWord) == 0: 659 # Just to make sure, erase all history trail: 660 self.eraseTrail(); 661 return; 662 oldNewestButton = self.getButtonFromEncodedLetter(self.encEvolvingWord[-1]); 663 self.encEvolvingWord = self.encEvolvingWord[0:-1]; 664 if len(self.encEvolvingWord) > 0: 665 newNewestButton = self.getButtonFromEncodedLetter(self.encEvolvingWord[-1]); 666 else: 667 newNewestButton = None; 668 self.shiftButtonTrails(HistoryShiftDir.YOUNGER, newHead=newNewestButton); 669 self.crossOutButton(oldNewestButton); 670 if len(self.encEvolvingWord) == 0: 671 self.eraseTrail();672674 ''' 675 Show the given button crossed out. Update the 676 currentButtonBackgrounds dict to show that this 677 button now has a different background (not one of the 678 trails. 679 @param buttonObj: GestureButton object to cross out. 680 @type buttonObj: QPushButton 681 ''' 682 self.setButtonImage(buttonObj, self.crossedOutButtonBackground); 683 self.crossedOutButtons.append(buttonObj); 684 # Take the crossout away in 2 seconds: 685 self.crossOutTimer.start(2000);686688 ''' 689 Erase the history trail. 690 ''' 691 for buttonObj in self.letterButtons: 692 self.setButtonImage(buttonObj, self.buttonBackGroundPixmaps[-1]); 693 self.currentButtonBackgrounds[buttonObj] = NUM_LETTER_BUTTONS - 1;694696 if direction == HistoryShiftDir.OLDER: 697 # Every button gets one older: 698 for buttonObj in self.letterButtons: 699 currPixmapIndex = self.currentButtonBackgrounds[buttonObj]; 700 if currPixmapIndex is None: 701 continue; 702 if currPixmapIndex >= NUM_LETTER_BUTTONS - 1: 703 # Button already as old as it gets: 704 continue; 705 buttonObj.setIcon(QIcon(self.buttonBackGroundPixmaps[currPixmapIndex + 1])); 706 self.currentButtonBackgrounds[buttonObj] = currPixmapIndex + 1; 707 if newHead is not None: 708 self.setButtonImage(newHead, self.buttonBackGroundPixmaps[0]); 709 self.currentButtonBackgrounds[newHead] = 0; 710 711 else: 712 # Make everyone younger: 713 for buttonObj in self.letterButtons: 714 currPixmapIndex = self.currentButtonBackgrounds[buttonObj]; 715 if currPixmapIndex is None: 716 # Button has a special, temporary background, like being crossed out: 717 continue; 718 if currPixmapIndex <= 0: 719 # Button already as young as it gets. Make it the oldest: 720 self.setButtonImage(buttonObj,self.buttonBackGroundPixmaps[NUM_LETTER_BUTTONS - 1]); 721 self.setButtonImage(buttonObj, self.buttonBackGroundPixmaps[currPixmapIndex - 1]); 722 self.currentButtonBackgrounds[buttonObj] = currPixmapIndex - 1;723 724726 # PySide: gestureButtonObj.setIcon(pixmap); 727 gestureButtonObj.setIcon(QIcon(pixmap)); 728 gestureButtonObj.setIconSize(pixmap.rect().size());729 730732 ''' 733 Prepare the Add New Word dialog, and show it: 734 @param newWord: 735 @type newWord: 736 ''' 737 # New word capitalized? Pre-set the Capitalize checkbox accordingly: 738 if newWord.istitle(): 739 self.addWordDialog.capitalizeCheckbox.setChecked(True); 740 else: 741 self.addWordDialog.capitalizeCheckbox.setChecked(False); 742 # Init the label in the dialog box that shows the word to be added: 743 self.addWordDialog.newWord.setText(newWord); 744 745 # Place the dialog somewhere over the application window: 746 tboardGeoRect = self.geometry(); 747 dialogGeoRect = self.addWordDialog.geometry(); 748 newDialogGeo = QRect(tboardGeoRect.x() + 50, 749 tboardGeoRect.y() + 50, 750 dialogGeoRect.width(), 751 dialogGeoRect.height()); 752 self.addWordDialog.setGeometry(newDialogGeo); 753 754 self.addWordDialog.show();755 756 # -------------------------------------- Handy Methods ------------------------- 757759 # From the encoded letter, get the corresponding 760 # "ABC", "PQR", etc label: 761 buttonLabel = self.wordCollection.decodeTelPadLabel(encLetter); 762 buttonID = ButtonID.toButtonID(buttonLabel); 763 return self.letterButtons[buttonID];
Home | Trees | Indices | Help |
---|
Generated by Epydoc 3.0.1 on Thu Feb 21 13:26:29 2013 | http://epydoc.sourceforge.net |