def __init__(self): super(Foo, self).__init__() self._action_set = None self._update_current_value_signal.connect(self._update_current_value) self._scene_notification = QDialog(main_window) ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'src', 'wrong_scene_dialog.ui') loadUi(ui_file, self._scene_notification) self._scene_notification_timer = QTimer(main_window) self._scene_notification_timer.setInterval(5000) self._scene_notification_timer.setSingleShot(True) self._scene_notification_timer.timeout.connect(self._hide_scene_notification) self._scene_notification.finished.connect(self._hide_scene_notification) self._input_notification = QDialog(main_window) ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'src', 'wrong_input_method_dialog.ui') loadUi(ui_file, self._input_notification) self._input_notification_timer = QTimer(main_window) self._input_notification_timer.setInterval(5000) self._input_notification_timer.setSingleShot(True) self._input_notification_timer.timeout.connect(self._hide_input_method_notification) self._input_notification.finished.connect(self._hide_input_method_notification) self._show_input_notification_signal.connect(self._show_input_notification) self._hide_input_notification_signal.connect(self._hide_input_method_notification) self._show_input_notification_signal.connect(self._show_scene_notification) self._hide_input_notification_signal.connect(self._hide_scene_notification) self._update_color_of_line_edit_signal.connect(self._update_color_of_line_edit)
def __init__(self, parent=None, model=None): QDialog.__init__(self, parent) assert isinstance(model, ScatteringModel) self._model = model self.setObjectName("AddRangeDialog") self.setWindowTitle("Add Range") self.setWindowModality(Qt.WindowModal) vlayout = QVBoxLayout(self) vlayout.setObjectName("vlayout") vlayout.addWidget(self._createEntries()) vlayout.addWidget(self._createButtons()) self.setLayout(vlayout)
def queue_dialog(): dialog = QDialog() ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'src', 'queue_dialog.ui') loadUi(ui_file, dialog) if current_name is not None: dialog.label_lineEdit.setText(current_name) dialog.username_lineEdit.setText(queue_default_username) dialog.password_lineEdit.setText(queue_default_password) rc = dialog.exec_() if rc == QDialog.Rejected: return queue_program(dialog.username_lineEdit.text(), dialog.password_lineEdit.text(), dialog.label_lineEdit.text())
def __init__(self): super(Foo, self).__init__() self._action_set = None self._update_current_value_signal.connect(self._update_current_value) self._scene_notification = QDialog(main_window) ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'src', 'wrong_scene_dialog.ui') loadUi(ui_file, self._scene_notification) self._scene_notification_timer = QTimer(main_window) self._scene_notification_timer.setInterval(5000) self._scene_notification_timer.setSingleShot(True) self._scene_notification_timer.timeout.connect( self._hide_scene_notification) self._scene_notification.finished.connect( self._hide_scene_notification) self._input_notification = QDialog(main_window) ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'src', 'wrong_input_method_dialog.ui') loadUi(ui_file, self._input_notification) self._input_notification_timer = QTimer(main_window) self._input_notification_timer.setInterval(5000) self._input_notification_timer.setSingleShot(True) self._input_notification_timer.timeout.connect( self._hide_input_method_notification) self._input_notification.finished.connect( self._hide_input_method_notification) self._show_input_notification_signal.connect( self._show_input_notification) self._hide_input_notification_signal.connect( self._hide_input_method_notification) self._show_input_notification_signal.connect( self._show_scene_notification) self._hide_input_notification_signal.connect( self._hide_scene_notification) self._update_color_of_line_edit_signal.connect( self._update_color_of_line_edit)
def initNewDictWordDialog(self): ''' Initializes dialog window for user to add a new word to the dictionary. ''' # Find QtCreator's XML file in the PYTHONPATH: currDir = os.path.realpath(__file__); relPathQtCreatorFile = "tboard_ui/addWord_dialog/addWordDialog.ui"; qtCreatorXMLFilePath = Utilities.findFile(relPathQtCreatorFile); if qtCreatorXMLFilePath is None: raise ValueError("Can't find QtCreator user interface file for 'new dictionary word' dialog file %s" % relPathQtCreatorFile); #****self.addWordDialog = QWidget(); self.addWordDialog = QDialog(); python_qt_binding.loadUi(qtCreatorXMLFilePath, self.addWordDialog); # Assign int IDs to the frequency checkboxes: rareButton = self.addWordDialog.useRarelyButton; occasionButton = self.addWordDialog.useOccasionallyButton; constantButton = self.addWordDialog.useConstantlyButton; self.addWordButtonGroup = QButtonGroup(); self.addWordButtonGroup.addButton(rareButton, TBoard.RARELY_BUTTON_ID); self.addWordButtonGroup.addButton(occasionButton, TBoard.OCCCASIONALLY_BUTTON_ID); self.addWordButtonGroup.addButton(constantButton, TBoard.CONSTANTLY_BUTTON_ID); self.addWordDialog.hide();
class Foo(QObject): current_values_changed = Signal(str) current_duration_changed = Signal(float) _update_current_value_signal = Signal() _show_input_notification_signal = Signal() _hide_input_notification_signal = Signal() _show_scene_notification_signal = Signal() _hide_scene_notification_signal = Signal() _update_color_of_line_edit_signal = Signal() def __init__(self): super(Foo, self).__init__() self._action_set = None self._update_current_value_signal.connect(self._update_current_value) self._scene_notification = QDialog(main_window) ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'src', 'wrong_scene_dialog.ui') loadUi(ui_file, self._scene_notification) self._scene_notification_timer = QTimer(main_window) self._scene_notification_timer.setInterval(5000) self._scene_notification_timer.setSingleShot(True) self._scene_notification_timer.timeout.connect( self._hide_scene_notification) self._scene_notification.finished.connect( self._hide_scene_notification) self._input_notification = QDialog(main_window) ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'src', 'wrong_input_method_dialog.ui') loadUi(ui_file, self._input_notification) self._input_notification_timer = QTimer(main_window) self._input_notification_timer.setInterval(5000) self._input_notification_timer.setSingleShot(True) self._input_notification_timer.timeout.connect( self._hide_input_method_notification) self._input_notification.finished.connect( self._hide_input_method_notification) self._show_input_notification_signal.connect( self._show_input_notification) self._hide_input_notification_signal.connect( self._hide_input_method_notification) self._show_input_notification_signal.connect( self._show_scene_notification) self._hide_input_notification_signal.connect( self._hide_scene_notification) self._update_color_of_line_edit_signal.connect( self._update_color_of_line_edit) def _hide_scene_notification(self, result=None): self._scene_notification_timer.stop() self._scene_notification.hide() def _hide_input_method_notification(self, result=None): self._input_notification_timer.stop() self._input_notification.hide() # this method is call by ROS, all UI interaction is delayed via signals def update_current_value(self): global check_collisions global currently_in_collision if self._action_set is not None: self._action_set.stop() self._action_set = kontrol_subscriber.get_action_set() if self._action_set is not None: self.current_duration_changed.emit(self._action_set.get_duration()) if not is_in_slider_mode(): currently_in_collision = False self._show_input_notification_signal.emit() return if self._input_notification_timer.isActive(): self._hide_input_notification_signal.emit() #print('update_current_value()') if not kontrol_subscriber.is_valid_action_set(): self._show_scene_notification_signal.emit() return if self._scene_notification_timer.isActive(): self._hide_scene_notification_signal.emit() joint_values = kontrol_subscriber.get_joint_values() if check_collisions: in_collision = collision_checker.is_in_collision(joint_values) else: in_collision = False collision_toggled = (currently_in_collision != in_collision) currently_in_collision = in_collision if collision_toggled: self._update_color_of_line_edit_signal.emit() self._update_current_value_signal.emit() def _show_input_notification(self): # open dialog which closes after some s_hide_scene_notification_hide_scene_notificationeconds or when confirmed manually self._input_notification.show() self._input_notification_timer.start() def _show_scene_notification(self): # open dialog which closes after some seconds or when confirmed manually self._scene_notification.show() self._scene_notification_timer.start() def _update_color_of_line_edit(self): global currently_in_collision palette = main_window.lineEdit.palette() if currently_in_collision: palette.setColor(QPalette.Text, QColor(255, 0, 0)) else: palette.setColor(QPalette.Text, default_color) main_window.lineEdit.setPalette(palette) def _update_current_value(self): global currently_in_collision main_window.append_pushButton.setEnabled(not currently_in_collision) main_window.insert_before_pushButton.setEnabled( not currently_in_collision) value = self._action_set.to_string() self.current_values_changed.emit(value) for action in self._action_set._actions: action._duration = 0.1 if use_sim_time else 0.5 self._action_set.execute()
def execute_current_sequence_from_selection(): row = get_selected_row() if row == get_row_count() - 1: row = None execute_sequence(get_current_tab_index(), row) main_window.run_sequence_from_selection_pushButton.clicked.connect( execute_current_sequence_from_selection) select_row_signal = RelaySignalInt() select_row_signal.relay_signal.connect(set_selected_row) collision_notification = QDialog(main_window) ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'src', 'collision_dialog.ui') loadUi(ui_file, collision_notification) collision_notification_timer = QTimer(main_window) collision_notification_timer.setInterval(3000) collision_notification_timer.setSingleShot(True) def hide_collision_notification(result=None): collision_notification_timer.stop() collision_notification.hide() collision_notification_timer.timeout.connect(hide_collision_notification) collision_notification.finished.connect(hide_collision_notification)
class Foo(QObject): current_values_changed = Signal(str) current_duration_changed = Signal(float) _update_current_value_signal = Signal() _show_input_notification_signal = Signal() _hide_input_notification_signal = Signal() _show_scene_notification_signal = Signal() _hide_scene_notification_signal = Signal() _update_color_of_line_edit_signal = Signal() def __init__(self): super(Foo, self).__init__() self._action_set = None self._update_current_value_signal.connect(self._update_current_value) self._scene_notification = QDialog(main_window) ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'src', 'wrong_scene_dialog.ui') loadUi(ui_file, self._scene_notification) self._scene_notification_timer = QTimer(main_window) self._scene_notification_timer.setInterval(5000) self._scene_notification_timer.setSingleShot(True) self._scene_notification_timer.timeout.connect(self._hide_scene_notification) self._scene_notification.finished.connect(self._hide_scene_notification) self._input_notification = QDialog(main_window) ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'src', 'wrong_input_method_dialog.ui') loadUi(ui_file, self._input_notification) self._input_notification_timer = QTimer(main_window) self._input_notification_timer.setInterval(5000) self._input_notification_timer.setSingleShot(True) self._input_notification_timer.timeout.connect(self._hide_input_method_notification) self._input_notification.finished.connect(self._hide_input_method_notification) self._show_input_notification_signal.connect(self._show_input_notification) self._hide_input_notification_signal.connect(self._hide_input_method_notification) self._show_input_notification_signal.connect(self._show_scene_notification) self._hide_input_notification_signal.connect(self._hide_scene_notification) self._update_color_of_line_edit_signal.connect(self._update_color_of_line_edit) def _hide_scene_notification(self, result=None): self._scene_notification_timer.stop() self._scene_notification.hide() def _hide_input_method_notification(self, result=None): self._input_notification_timer.stop() self._input_notification.hide() # this method is call by ROS, all UI interaction is delayed via signals def update_current_value(self): global check_collisions global currently_in_collision if self._action_set is not None: self._action_set.stop() self._action_set = kontrol_subscriber.get_action_set() if self._action_set is not None: self.current_duration_changed.emit(self._action_set.get_duration()) if not is_in_slider_mode(): currently_in_collision = False self._show_input_notification_signal.emit() return if self._input_notification_timer.isActive(): self._hide_input_notification_signal.emit() #print('update_current_value()') if not kontrol_subscriber.is_valid_action_set(): self._show_scene_notification_signal.emit() return if self._scene_notification_timer.isActive(): self._hide_scene_notification_signal.emit() joint_values = kontrol_subscriber.get_joint_values() if check_collisions: in_collision = collision_checker.is_in_collision(joint_values) else: in_collision = False collision_toggled = (currently_in_collision != in_collision) currently_in_collision = in_collision if collision_toggled: self._update_color_of_line_edit_signal.emit() self._update_current_value_signal.emit() def _show_input_notification(self): # open dialog which closes after some s_hide_scene_notification_hide_scene_notificationeconds or when confirmed manually self._input_notification.show() self._input_notification_timer.start() def _show_scene_notification(self): # open dialog which closes after some seconds or when confirmed manually self._scene_notification.show() self._scene_notification_timer.start() def _update_color_of_line_edit(self): global currently_in_collision palette = main_window.lineEdit.palette() if currently_in_collision: palette.setColor(QPalette.Text, QColor(255, 0, 0)) else: palette.setColor(QPalette.Text, default_color) main_window.lineEdit.setPalette(palette) def _update_current_value(self): global currently_in_collision main_window.append_pushButton.setEnabled(not currently_in_collision) main_window.insert_before_pushButton.setEnabled(not currently_in_collision) value = self._action_set.to_string() self.current_values_changed.emit(value) for action in self._action_set._actions: action._duration = 0.1 if use_sim_time else 0.5 self._action_set.execute()
class TBoard(QWidget): # Ids for checkboxes in the 'add-new-word' dialog: RARELY_BUTTON_ID = 0; OCCCASIONALLY_BUTTON_ID = 1; CONSTANTLY_BUTTON_ID = 2; def __init__(self): super(TBoard, self).__init__(); self.setWindowTitle("TBoard"); # Find QtCreator's XML file in the PYTHONPATH: currDir = os.path.realpath(__file__); relPathQtCreatorFile = "tboard_ui/tboard_ui.ui"; qtCreatorXMLFilePath = Utilities.findFile(relPathQtCreatorFile); if qtCreatorXMLFilePath is None: raise ValueError("Can't find QtCreator user interface file %s" % relPathQtCreatorFile); # Make QtCreator generated UI a child if this instance: python_qt_binding.loadUi(qtCreatorXMLFilePath, self); self.letterWidgets = [self.ABCWidget, self.DEFWidget, self.GHIWidget, self.JKLWidget, self.MNOWidget, self.PQRWidget, self.STUVWidget, self.WXYZWidget]; self.createColors(); # Populate all empty letter board button widgets with # GestureButton instances: self.populateGestureButtons(); self.preparePixmaps(); # Increase the width of the word area scrollbar: self.wordList.verticalScrollBar().setFixedWidth(WORD_LIST_SCROLLBAR_WIDTH) # pixels # Where we accumulate evolving words in encoded form # (see symbolToEnc dict in word_collection.py): self.encEvolvingWord = ""; self.currButtonUsedForFlick = False; self.wordCollection = TelPadEncodedWordCollection(); # Timer to ensure that a crossed-out button doesn't # stay crossed out forever: self.crossOutTimer = QTimer(); self.crossOutTimer.setSingleShot(True); self.crossedOutButtons = []; # Popup dialog for adding new words to dictionary: self.initNewDictWordDialog(); # Gesture buttons all in Dialpad (speed-write mode): self.buttonEditMode = ButtonEditMode.DIALPAD; # Disable selecting for the remaining-words panel: self.wordList.setFocusPolicy(Qt.NoFocus); # Mutex for keeping very fast flicking gestures # out of each others' hair: self.mutex = QMutex(); # The system clipboard for copy: self.clipboard = QApplication.clipboard(); # Speak-button not working yet: self.speakButton.setDisabled(True); self.connectWidgets(); #self.setGeometry(500, 500, 300, 100); self.show(); # -------------------------------------- UI Setup Methods ------------------------- def initNewDictWordDialog(self): ''' Initializes dialog window for user to add a new word to the dictionary. ''' # Find QtCreator's XML file in the PYTHONPATH: currDir = os.path.realpath(__file__); relPathQtCreatorFile = "tboard_ui/addWord_dialog/addWordDialog.ui"; qtCreatorXMLFilePath = Utilities.findFile(relPathQtCreatorFile); if qtCreatorXMLFilePath is None: raise ValueError("Can't find QtCreator user interface file for 'new dictionary word' dialog file %s" % relPathQtCreatorFile); #****self.addWordDialog = QWidget(); self.addWordDialog = QDialog(); python_qt_binding.loadUi(qtCreatorXMLFilePath, self.addWordDialog); # Assign int IDs to the frequency checkboxes: rareButton = self.addWordDialog.useRarelyButton; occasionButton = self.addWordDialog.useOccasionallyButton; constantButton = self.addWordDialog.useConstantlyButton; self.addWordButtonGroup = QButtonGroup(); self.addWordButtonGroup.addButton(rareButton, TBoard.RARELY_BUTTON_ID); self.addWordButtonGroup.addButton(occasionButton, TBoard.OCCCASIONALLY_BUTTON_ID); self.addWordButtonGroup.addButton(constantButton, TBoard.CONSTANTLY_BUTTON_ID); self.addWordDialog.hide(); def populateGestureButtons(self): ''' Creates GestureButton instances for each telephone pad button. Creates convenience data structures: - C{letterButtons} is an array of all GestureButton instances - C{letterButtonToID} maps GestureButton instances to the buttons' IDs, which happen to be their label strings ('ABC', 'DEF', etc.). - C{idToLetterButton} is the reverse: a dictionary mapping button labels, like "ABC" to the corresponding button instance. This function also sets style sheets for the all GestureButton instances. ''' # Sorted array of all letter button objs: self.letterButtons = []; # Letter button object to button label: "ABC", "DEF", etc: self.letterButtonToID = {}; self.idToLetterButton = {}; for buttonID in ButtonID.legalValues: self.letterButtons.append(GestureButton(ButtonID.toString(buttonID), parent=self.letterWidgets[buttonID])); self.letterButtonToID[self.letterButtons[-1]] = self.letterButtons[-1].text(); self.letterButtons[-1].setGeometry(0,0,200,100); self.idToLetterButton[self.letterButtons[-1].text()] = self.letterButtons[-1]; for buttonObj in self.letterButtons: self.setGestureButtonStyle(buttonObj, StyleID.RELEASED); #****buttonObj.setFocusPolicy(Qt.FocusPolicy.NoFocus); buttonObj.setFocusPolicy(Qt.NoFocus); def connectWidgets(self): ''' Connect signals and button slots to their handlers. ''' CommChannel.getSignal('GestureSignals.flickSig').connect(self.handleButtonFlicks); CommChannel.getSignal('GestureSignals.buttonEnteredSig').connect(self.handleButtonEntered); CommChannel.getSignal('GestureSignals.buttonExitedSig').connect(self.handleButtonExited); self.eraseWordButton.clicked.connect(self.handleEraseWordButton); self.addWordButton.clicked.connect(self.handleSaveWordButton); self.crossOutTimer.timeout.connect(self.handleCrossoutTimeout); # Number pad: for button in set([self.numPad1, self.numPad2, self.numPad3, self.numPad4, self.numPad5, self.numPad6, self.numPad7, self.numPad8, self.numPad9, self.numPad0]): button.clicked.connect(partial(self.handleNumPad, button)); # Special characters: for button in set([self.commaButton, self.colonButton, self.questionButton, self.atButton, self.leftParenButton, self.periodButton, self.backspaceButton, self.slashButton, self.spaceButton, self.rightParenButton]): button.clicked.connect(partial(self.handleSpecialChars, button)); # Gesture button clicks (switching between dialpad and letter mode: for buttonObj in self.letterButtons: buttonObj.clicked.connect(partial(self.handleGestureButtonClick, buttonObj)); # Add word dialog box capitalization checkbox state changed: self.addWordDialog.capitalizeCheckbox.stateChanged.connect(self.handleAddDictWordCapitalizeStateChanged); # Add word dialog box OK or Cancel botton clicked: self.addWordDialog.cancelButton.clicked.connect(partial(self.handleAddDictWordOK_Cancel, self.addWordDialog.cancelButton)); self.addWordDialog.addWordButton.clicked.connect(partial(self.handleAddDictWordOK_Cancel, self.addWordDialog.addWordButton)); # CopyAll button: self.copyButton.clicked.connect(self.handleCopyAll); def preparePixmaps(self): ''' Pull icons from the file system, and turn them into pixmaps. ''' imgDirPath = os.path.join(os.path.dirname(__file__), "img/"); self.buttonBackGroundPixmaps = []; buttonWidth = self.letterButtons[0].width(); buttonHeight = self.letterButtons[0].height(); for backgroundImgNum in range(NUM_LETTER_BUTTONS): buttonPixmap = QPixmap(); #****imgPath = os.path.join(imgDirPath, "tboardButtonBackgroundTrail" + str(backgroundImgNum + 1) + ".png"); imgPath = os.path.join(imgDirPath, "tboardButtonBackgroundsSmall" + str(backgroundImgNum + 1) + ".png"); if not buttonPixmap.load(imgPath): raise IOError("Could not find button background icon at " + imgPath); #scaledPixmap = buttonPixmap.scaled(buttonWidth, buttonHeight); #*****scaledPixmap = buttonPixmap.scaled(buttonWidth + 50, buttonHeight); scaledPixmap = buttonPixmap; #***** self.buttonBackGroundPixmaps.append(scaledPixmap); self.crossedOutButtonBackground = QPixmap(); imgPath = os.path.join(imgDirPath, "tboardButtonBackgroundCrossedOut.png"); if not self.crossedOutButtonBackground.load(imgPath): raise IOError("Could not find crossed-out button background icon at " + imgPath); self.crossedOutButtonBackground = self.crossedOutButtonBackground.scaled(buttonWidth + 50, buttonHeight); # Initialize all buttons to a background with # trail spot 8 (darkest): for button in self.letterButtons: self.setButtonImage(button, self.buttonBackGroundPixmaps[NUM_LETTER_BUTTONS - 1]); # Initialize dictionary that tracks button background icons. # Keys are button objs, values are ints that index into the # self.buttonBackgroundPixmaps array. None means the button # is so old that it has a plain background, or that it was never # used so far: self.currentButtonBackgrounds = {}; for buttonObj in self.letterButtons: self.currentButtonBackgrounds[buttonObj] = None; self.setStyleSheet("QWidget{background-color: %s}" % self.offWhiteColor.name()); def createColors(self): ''' Create QColor objects from RGB values. ''' self.grayBlueColor = QColor(89,120,137); # Letter buttons self.offWhiteColor = QColor(206,230,243); # Background self.darkGray = QColor(65,88,101); # Central buttons self.wordListFontColor = QColor(62,143,185); # Darkish blue. self.purple = QColor(147,124,195); # Gesture button pressed def setGestureButtonStyle(self, buttonObj, styleID): ''' Style a gesture button. @param buttonObj: the button to style @type buttonObj: GestureButton @param styleID: whether button is pressed or released @type styleID: StyleID ''' if styleID == StyleID.RELEASED: buttonObj.setStyleSheet("background-color: %s; color: %s; border: 2px outset %s; border-radius: 15; font-size: 18px" % (self.grayBlueColor.name(), self.offWhiteColor.name(), self.offWhiteColor.name())); elif styleID == StyleID.PRESSED: buttonObj.setStyleSheet("background-color: %s; color: %s; border-radius: 15; font-size: 22px" % (self.purple.name(), self.offWhiteColor.name())); self.setFocus(); # -------------------------------------- Signal Handlers ------------------------- @Slot(GestureButton, int) def handleButtonFlicks(self, gestureButton, flickDirection): ''' Action on flicking in and out of a gesture button. @param gestureButton: button that was flicked @type gestureButton: GestureButton @param flickDirection: cursor flicked North, South, East, or West @type flickDirection: GestureButton.FlickDirection ''' #print "Flick direction: " + FlickDirection.toString(flickDirection); # Protect against re-entry. Not that # QtCore.QMutexLocker locks when created, and # unlocks when destroyed (i.e. when function # is left; no explicit unlocking needed); myMutexLocker = QMutexLocker(self.mutex); # West flick: Undo last letter (in Dialpad mode) or # highlight next letter (in Letter_Edit mod): if flickDirection == FlickDirection.WEST: if self.buttonEditMode == ButtonEditMode.DIALPAD: self.erasePreviousLetter(); self.showRemainingWords(); self.updateTickerTape(); else: # individual-letter-input mode: self.highlightNextLetter(gestureButton, FlickDirection.WEST); # North flick: Scroll word list up: elif flickDirection == FlickDirection.NORTH: currRemainingWordsRow = self.wordList.currentRow(); if currRemainingWordsRow == 0 or self.buttonEditMode == ButtonEditMode.LETTER_INPUT: pass; else: self.wordList.setCurrentRow(currRemainingWordsRow - 1); # South flick: Scroll word list down: elif flickDirection == FlickDirection.SOUTH: currRemainingWordsRow = self.wordList.currentRow(); if currRemainingWordsRow >= self.wordList.count() or self.buttonEditMode == ButtonEditMode.LETTER_INPUT: pass; else: self.wordList.setCurrentRow(currRemainingWordsRow + 1); # East flick: Accept word that is selected in remaining words list: else: if self.buttonEditMode == ButtonEditMode.LETTER_INPUT: self.highlightNextLetter(gestureButton, FlickDirection.EAST); else: # No word in word list? count = self.wordList.count() currItem = self.wordList.currentItem(); if count <= 0 or currItem is None: pass; else: self.outputPanel.insertPlainText(" " + currItem.text()); # Word entry done for this word: self.eraseCurrentWord(); # Remember that we just used this button # for a flick action. self.currButtonUsedForFlick = True; @Slot(GestureButton) def handleButtonEntered(self, gestureButtonObj): #print "Button %s entered" % str(gestureButtonObj); pass; @Slot(GestureButton) def handleButtonExited(self, gestureButtonObj): ''' Handler for cursor having entered a gesture button. @param gestureButtonObj: button object that was entered @type gestureButtonObj: GestureButton ''' # Protect against re-entry. Not that # QtCore.QMutexLocker locks when created, and # unlocks when destroyed (i.e. when function # is left; no explicit unlocking needed); myMutexLocker = QMutexLocker(self.mutex); # If we are in letter entry mode, return this button # to Dialpad mode: if self.buttonEditMode == ButtonEditMode.LETTER_INPUT: self.switchButtonMode(gestureButtonObj, ButtonEditMode.DIALPAD); return; # If button being left was just used for a flick, # don't count the exit: if self.currButtonUsedForFlick: self.currButtonUsedForFlick = False; return; # Get 'ABC', or 'DEF', etc representation from the button: buttonLabelAsStr = str(gestureButtonObj); newEncLetter = self.wordCollection.encodeTelPadLabel(buttonLabelAsStr); self.encEvolvingWord += newEncLetter; self.shiftButtonTrails(HistoryShiftDir.OLDER, newHead=gestureButtonObj); #print self.encEvolvingWord; self.showRemainingWords(); self.updateTickerTape(); def handleEraseWordButton(self): ''' Handler for erase-word button clicked. ''' self.eraseCurrentWord(); self.showRemainingWords(); self.updateTickerTape(); def handleCrossoutTimeout(self): ''' Timeout handler that detects crossing out a letter by running through a gesture button and back. ''' for buttonObj in self.crossedOutButtons: self.setButtonImage(buttonObj, self.buttonBackGroundPixmaps[self.currentButtonBackgrounds[buttonObj]]); self.crossedOutButtons = []; def handleNumPad(self, numButton): ''' Handler for number pad button pressed. @param numButton: button object @type numButton: QPushButton ''' buttonLabel = numButton.text(); self.outputPanel.insertPlainText(buttonLabel); def handleSpecialChars(self, specCharButton): ''' Handler: special character button pushed. @param specCharButton: button object @type specCharButton: QPushButton ''' if specCharButton == self.backspaceButton: self.outputPanel.textCursor().deletePreviousChar(); return; elif specCharButton == self.spaceButton: char = " "; else: char = specCharButton.text(); self.outputPanel.insertPlainText(char); def handleGestureButtonClick(self, buttonObj): ''' Handler for gesture button click. @param buttonObj: Button object @type buttonObj: GestureButton ''' # If button is in default dialpad mode, switch to letter-input mode: if self.buttonEditMode == ButtonEditMode.DIALPAD: self.switchButtonMode(buttonObj, ButtonEditMode.LETTER_INPUT); # If button is in letter edit mode, add the currently # capitalized letter to the output panel, and switch the # button back into default dialpad mode: elif self.buttonEditMode == ButtonEditMode.LETTER_INPUT: labelBeingEdited = buttonObj.text(); capLetter = labelBeingEdited[self.findCapitalLetter(labelBeingEdited)]; self.outputPanel.insertPlainText(capLetter.lower()); self.switchButtonMode(buttonObj, ButtonEditMode.DIALPAD); def handleSaveWordButton(self): # Get content of output panel: currOutput = self.outputPanel.toPlainText(); # If noth'n there, done: if len(currOutput) == 0: QMessageBox.information(self, "Dictionary addition", "Output panel has no content; so there is no word to save.", QMessageBox.Ok, QMessageBox.NoButton); return; # Get the last word in the output panel: newWord = re.split("[.;:?! @()]", currOutput)[-1]; # Ask user about capitalization, and expected word frequency. # This call will raise a modal dialog box. Signal handlers # handleAddDictWordCapitalizeStateChanged(), and handleAddDictWordOK_Cancel() # take it from there: self.getAddWordUserInfo(newWord); def handleAddDictWordCapitalizeStateChanged(self, newCapsState): dialog = self.addWordDialog; newWord = dialog.newWord.text(); if newCapsState == 0: dialog.newWord.setText(newWord.lower()); else: dialog.newWord.setText(newWord.capitalize()); def handleAddDictWordOK_Cancel(self, button): if button == self.addWordDialog.cancelButton: self.addWordDialog.hide(); return; frequencyCheckboxID = self.addWordButtonGroup.checkedId(); if frequencyCheckboxID == TBoard.RARELY_BUTTON_ID: freqRank = UseFrequency.RARELY; elif frequencyCheckboxID == TBoard.OCCCASIONALLY_BUTTON_ID: freqRank = UseFrequency.OCCASIONALLY; elif frequencyCheckboxID == TBoard.CONSTANTLY_BUTTON_ID: freqRank = UseFrequency.CONSTANTLY; else: raise ValueError("Unknown use frequency checkbox ID in add word to dictionary dialog handling: " + str(frequencyCheckboxID)); self.doAddWordButton(self.addWordDialog.newWord.text(), freqRank); self.addWordDialog.hide(); def handleCopyAll(self): self.clipboard.setText(self.outputPanel.toPlainText()); # -------------------------------------- UI Manipulation ------------------------- def doAddWordButton(self, newWord, rank): additionResult = self.wordCollection.addToUserDict(newWord, rankInt=rank); if additionResult: QMessageBox.information(self, # dialog parent "Dictionary addition", "Word '%s' has been saved in user dictionary." % newWord, QMessageBox.Ok, QMessageBox.NoButton); else: QMessageBox.information(self, # dialog parent "Dictionary addition", "Word '%s' was already in the dictionary. No action taken" % newWord, QMessageBox.Ok, QMessageBox.NoButton); def switchButtonMode(self, buttonObj, newEditMode): if newEditMode == ButtonEditMode.DIALPAD: self.setGestureButtonStyle(buttonObj, StyleID.RELEASED); self.buttonEditMode = ButtonEditMode.DIALPAD; buttonObj.setText(buttonObj.text().upper()); elif newEditMode == ButtonEditMode.LETTER_INPUT: self.setGestureButtonStyle(buttonObj, StyleID.PRESSED); self.buttonEditMode = ButtonEditMode.LETTER_INPUT; buttonObj.setText(buttonObj.text().capitalize()); def highlightNextLetter(self, buttonObj, flickDirection): label = buttonObj.text(); capitalLetterPos = self.findCapitalLetter(label); label = label.lower(); if flickDirection == FlickDirection.EAST: newCapPos = (capitalLetterPos + 1) % len(label); else: newCapPos = (capitalLetterPos - 1) % len(label); #label = label[:newCapPos] + label[newCapPos].upper() + label[min(newCapPos + 1, len(label) - 1):]; label = label[:newCapPos] + label[newCapPos].upper() + label[newCapPos + 1:] if newCapPos < len(label) else ""; buttonObj.setText(label); def findCapitalLetter(self, word): for (pos, char) in enumerate(word): if char.isupper(): return pos; raise ValueError("No capital letter found."); def updateTickerTape(self): if len(self.encEvolvingWord) == 0: self.tickerTape.setText(""); return; visibleEncoding = ""; for encChar in self.encEvolvingWord: dialpadButtonLabel = self.wordCollection.decodeTelPadLabel(encChar); buttonID = ButtonID.toButtonID(dialpadButtonLabel); visibleEncoding += ButtonID.idToStringable(buttonID); self.tickerTape.setText(visibleEncoding); def showRemainingWords(self): remainingWords = self.wordCollection.prefix_search(self.encEvolvingWord); rankSortedWords = sorted(remainingWords, key=self.wordCollection.rank); self.wordList.clear(); self.wordList.addItems(rankSortedWords); self.wordList.setCurrentRow(0); #print self.wordCollection.prefix_search(self.encEvolvingWord); def eraseCurrentWord(self): self.encEvolvingWord = ""; self.updateTickerTape(); self.eraseTrail(); self.wordList.clear(); def erasePreviousLetter(self): if len(self.encEvolvingWord) == 0: # Just to make sure, erase all history trail: self.eraseTrail(); return; oldNewestButton = self.getButtonFromEncodedLetter(self.encEvolvingWord[-1]); self.encEvolvingWord = self.encEvolvingWord[0:-1]; if len(self.encEvolvingWord) > 0: newNewestButton = self.getButtonFromEncodedLetter(self.encEvolvingWord[-1]); else: newNewestButton = None; self.shiftButtonTrails(HistoryShiftDir.YOUNGER, newHead=newNewestButton); self.crossOutButton(oldNewestButton); if len(self.encEvolvingWord) == 0: self.eraseTrail(); def crossOutButton(self, buttonObj): ''' Show the given button crossed out. Update the currentButtonBackgrounds dict to show that this button now has a different background (not one of the trails. @param buttonObj: GestureButton object to cross out. @type buttonObj: QPushButton ''' self.setButtonImage(buttonObj, self.crossedOutButtonBackground); self.crossedOutButtons.append(buttonObj); # Take the crossout away in 2 seconds: self.crossOutTimer.start(2000); def eraseTrail(self): ''' Erase the history trail. ''' for buttonObj in self.letterButtons: self.setButtonImage(buttonObj, self.buttonBackGroundPixmaps[-1]); self.currentButtonBackgrounds[buttonObj] = NUM_LETTER_BUTTONS - 1; def shiftButtonTrails(self, direction, newHead=None): if direction == HistoryShiftDir.OLDER: # Every button gets one older: for buttonObj in self.letterButtons: currPixmapIndex = self.currentButtonBackgrounds[buttonObj]; if currPixmapIndex is None: continue; if currPixmapIndex >= NUM_LETTER_BUTTONS - 1: # Button already as old as it gets: continue; buttonObj.setIcon(QIcon(self.buttonBackGroundPixmaps[currPixmapIndex + 1])); self.currentButtonBackgrounds[buttonObj] = currPixmapIndex + 1; if newHead is not None: self.setButtonImage(newHead, self.buttonBackGroundPixmaps[0]); self.currentButtonBackgrounds[newHead] = 0; else: # Make everyone younger: for buttonObj in self.letterButtons: currPixmapIndex = self.currentButtonBackgrounds[buttonObj]; if currPixmapIndex is None: # Button has a special, temporary background, like being crossed out: continue; if currPixmapIndex <= 0: # Button already as young as it gets. Make it the oldest: self.setButtonImage(buttonObj,self.buttonBackGroundPixmaps[NUM_LETTER_BUTTONS - 1]); self.setButtonImage(buttonObj, self.buttonBackGroundPixmaps[currPixmapIndex - 1]); self.currentButtonBackgrounds[buttonObj] = currPixmapIndex - 1; def setButtonImage(self, gestureButtonObj, pixmap): # PySide: gestureButtonObj.setIcon(pixmap); gestureButtonObj.setIcon(QIcon(pixmap)); gestureButtonObj.setIconSize(pixmap.rect().size()); def getAddWordUserInfo(self, newWord): ''' Prepare the Add New Word dialog, and show it: @param newWord: @type newWord: ''' # New word capitalized? Pre-set the Capitalize checkbox accordingly: if newWord.istitle(): self.addWordDialog.capitalizeCheckbox.setChecked(True); else: self.addWordDialog.capitalizeCheckbox.setChecked(False); # Init the label in the dialog box that shows the word to be added: self.addWordDialog.newWord.setText(newWord); # Place the dialog somewhere over the application window: tboardGeoRect = self.geometry(); dialogGeoRect = self.addWordDialog.geometry(); newDialogGeo = QRect(tboardGeoRect.x() + 50, tboardGeoRect.y() + 50, dialogGeoRect.width(), dialogGeoRect.height()); self.addWordDialog.setGeometry(newDialogGeo); self.addWordDialog.show(); # -------------------------------------- Handy Methods ------------------------- def getButtonFromEncodedLetter(self, encLetter): # From the encoded letter, get the corresponding # "ABC", "PQR", etc label: buttonLabel = self.wordCollection.decodeTelPadLabel(encLetter); buttonID = ButtonID.toButtonID(buttonLabel); return self.letterButtons[buttonID];