/** TagButton instances are converted with whitespaces in the LineEdit in order to move them. */ void TagLineEdit::insertSpaces() { TagButton *t = qobject_cast<TagButton*>(sender()); int cx = cursorRect().x(); t->setPosition(cursorPosition()); int numberOfSpace = 2; this->setText(this->text().insert(cursorPosition(), " ")); cursorForward(false, 2); while (t->frameGeometry().contains(cursorRect().center())) { this->setText(this->text().insert(cursorPosition(), " ")); cursorForward(false); numberOfSpace++; } t->setMinimumWidth(numberOfSpace * fontMetrics().width(" ") - 5); t->setSpaceCount(numberOfSpace); t->disconnect(); for (TagButton *tag : _tags) { //qDebug() << Q_FUNC_INFO << "trying to move tag"; if (t != tag && tag->frameGeometry().x() > cx) { //qDebug() << Q_FUNC_INFO << "moving tag" << tag->text(); tag->move(tag->x() + fontMetrics().width(" ") * numberOfSpace, 0); } } }
/** Redefined to be able to move TagButton when typing. */ void TagLineEdit::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Left || event->key() == Qt::Key_Right) { /// TODO cursorWordForward / cursorWordBackard to stop on TagButton if (QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) { qDebug() << "cursorWordForward / backward"; } LineEdit::keyPressEvent(event); for (TagButton *t : _tags) { if (t->frameGeometry().contains(cursorRect().center())) { if (event->key() == Qt::Key_Left) { cursorBackward(false, t->spaceCount() - 1); } else { cursorForward(false, t->spaceCount() - 1); } break; } } } else { QString k = event->text(); int w = fontMetrics().width(k); if (event->key() == Qt::Key_Delete) { qDebug() << Q_FUNC_INFO << "Key_Delete"; w = -w; } for (TagButton *t : _tags) { if (t->frameGeometry().x() > cursorRect().center().x()) { t->move(t->x() + w, 0); } } LineEdit::keyPressEvent(event); } }
void CharLineEdit::keyPressEvent(QKeyEvent* event) { bool handled = false; if (selectionStart() == -1) { switch (event->key()) { case Qt::Key_Backspace: if (isAtEndOfSeparator()) { // Delete separator characters in a single keypress. // Don't use setText This method maintains the undo history backspace(); backspace(); backspace(); handled = true; } break; case Qt::Key_Delete: if (isAtStartOfSeparator()) { del(); del(); del(); handled = true; } break; case Qt::Key_Left: if (isAtEndOfSeparator()) { cursorBackward(false, 3); handled = true; } break; case Qt::Key_Right: if (isAtStartOfSeparator()) { cursorForward(false, 3); handled = true; } break; } } if (handled) { event->ignore(); } else { QLineEdit::keyPressEvent(event); } emit keyPressed(event); }
/** Redefined to be able to move tag buttons. * Backspace method is not virtual in QLineEdit, therefore keyPressEvent must be intercepted and eaten. */ void TagLineEdit::backspace() { bool oneTagNeedToBeRemoved = false; TagButton *tag = nullptr; QPoint cursorCenter; cursorBackward(false); int dx = fontMetrics().width(text().at(cursorPosition())); for (TagButton *button : _tags) { cursorCenter = cursorRect().center(); // One tag button need to be removed if (button->frameGeometry().contains(cursorCenter)) { oneTagNeedToBeRemoved = true; tag = button; } // Tags need to be moved to the left if (button->x() > cursorCenter.x()) { button->move(button->x() - dx, 0); button->setPosition(cursorPosition()); } } cursorForward(false); if (oneTagNeedToBeRemoved) { for (int i = 0; i < tag->spaceCount(); i++) { LineEdit::backspace(); } dx = fontMetrics().width(" ") * tag->spaceCount(); for (TagButton *button : _tags) { if (button != tag && button->x() > cursorCenter.x()) { button->move(button->x() - dx, 0); button->setPosition(cursorPosition()); } } _tags.removeOne(tag); delete tag; /// FIXME //emit taglistHasChanged(this->toStringList()); } else { LineEdit::backspace(); } }
/** Redefined to automatically move cursor outside TagButton. */ void TagLineEdit::mousePressEvent(QMouseEvent *event) { LineEdit::mousePressEvent(event); for (TagButton *t : _tags) { QRect r = t->frameGeometry(); if (r.contains(event->pos())) { if (r.x() + r.width() / 2 >= event->pos().x()) { while (r.contains(cursorRect().center()) && cursorPosition() > 0) { cursorBackward(false); //qDebug() << "cursorBackward" << "pos" << t->position() << "spaces" << t->spaceCount(); } } else { while (r.contains(cursorRect().center()) && cursorPosition() < text().length()) { cursorForward(false); //qDebug() << "cursorForward" << "pos" << t->position() << "spaces" << t->spaceCount(); } } break; } } }
void H19::processCharacter(char ch) { // mask off the high bit just in case, the real H19 would not have it set. ch &= 0x7f; if (mode_m == Normal) { switch (ch) { case ascii::NUL: case ascii::SOH: case ascii::STX: case ascii::ETX: case ascii::EOT: case ascii::ENQ: case ascii::ACK: case ascii::VT: case ascii::FF: case ascii::SO: case ascii::SI: case ascii::DLE: case ascii::DC1: case ascii::DC2: case ascii::DC3: case ascii::DC4: case ascii::NAK: case ascii::SYN: case ascii::ETB: case ascii::EM: case ascii::SUB: case ascii::FS: case ascii::GS: case ascii::RS: case ascii::US: case ascii::DEL: // From manual, these characters are not processed by the terminal break; case ascii::BEL: // Rings the bell. /// \todo - implement ringing bell. consoleLog("<BEL>"); break; case ascii::BS: // Backspace consoleLog("<BS>"); processBS(); break; case ascii::HT: // Horizontal Tab consoleLog("<TAB>"); processTAB(); break; case ascii::LF: // Line Feed processLF(); if (autoCR_m) { processCR(); } consoleLog("\n"); break; case ascii::CR: // Carriage Return processCR(); if (autoLF_m) { processLF(); } break; case ascii::CAN: // Cancel. break; case ascii::ESC: // Escape mode_m = Escape; consoleLog("<ESC>"); break; default: // if Printable character display it. #if CONSOLE_LOG fprintf(console_out, "%c", ch); #endif displayCharacter(ch); break; } } else if (mode_m == Escape) { // Assume we go back to Normal, so only the few that don't need to set the mode. mode_m = Normal; switch (ch) { case ascii::CAN: // CAN - Cancel // return to Normal mode, already set. break; case ascii::ESC: // Escape // From the ROM listing, stay in this mode. mode_m = Escape; break; // Cursor Functions case 'H': // Cursor Home posX_m = posY_m = 0; updated_m = true; break; case 'C': // Cursor Forward cursorForward(); break; case 'D': // Cursor Backward processBS(); // same processing as cursor backward break; case 'B': // Cursor Down cursorDown(); break; case 'A': // Cursor Up cursorUp(); break; case 'I': // Reverse Index reverseIndex(); break; case 'n': // Cursor Position Report cursorPositionReport(); break; case 'j': // Save cursor position saveCursorPosition(); break; case 'k': // Restore cursor position restoreCursorPosition(); break; case 'Y': // Direct Cursor Addressing mode_m = DCA_1; break; // Erase and Editing case 'E': // Clear Display clearDisplay(); break; case 'b': // Erase Beginning of Display eraseBOD(); break; case 'J': // Erase to End of Page eraseEOP(); break; case 'l': // Erase entire Line eraseEL(); break; case 'o': // Erase Beginning Of Line eraseBOL(); break; case 'K': // Erase To End Of Line eraseEOL(); break; case 'L': // Insert Line insertLine(); break; case 'M': // Delete Line deleteLine(); break; case 'N': // Delete Character deleteChar(); break; case '@': // Enter Insert Character Mode insertMode_m = true; break; case 'O': // Exit Insert Character Mode insertMode_m = false; break; // Configuration case 'z': // Reset To Power-Up Configuration reset(); break; case 'r': // Modify the Baud Rate /// \todo - determine if we should support this. debugss(ssH19, ERROR, "Error Unimplemented Modify Baud\n"); break; case 'x': // Set Mode mode_m = SetMode; break; case 'y': // Reset Mode mode_m = ResetMode; break; case '<': // Enter ANSI Mode /// \todo - implement ANSI mode. // ROM - just sets the mode debugss(ssH19, ERROR, "Error Entering ANSI mode - unsupported\n"); break; // Modes of operation case '[': // Enter Hold Screen Mode holdScreen_m = true; break; case '\\': // Exit Hold Screen Mode holdScreen_m = false; break; case 'p': // Enter Reverse Video Mode reverseVideo_m = true; break; case 'q': // Exit Reverse Video Mode reverseVideo_m = false; break; case 'F': // Enter Graphics Mode graphicMode_m = true; break; case 'G': // Exit Graphics Mode graphicMode_m = false; break; case 't': // Enter Keypad Shifted Mode keypadShifted_m = true; break; case 'u': // Exit Keypad Shifted Mode // ROM - just sets the mode keypadShifted_m = false; break; case '=': // Enter Alternate Keypad Mode // ROM - just sets the mode keypadShifted_m = true; break; case '>': // Exit Alternate Keypad Mode // ROM - just sets the mode keypadShifted_m = false; break; // Additional Functions case '}': // Keyboard Disable /// \todo - determine whether to do this. keyboardEnabled_m = false; break; case '{': // Keyboard Enable keyboardEnabled_m = true; break; case 'v': // Wrap Around at End Of Line wrapEOL_m = true; break; case 'w': // Discard At End Of Line wrapEOL_m = false; break; case 'Z': // Identify as VT52 (Data: ESC / K) debugss(ssH19, ERROR, "Identify request\n"); sendData(ascii::ESC); sendData('/'); sendData('K'); break; case ']': // Transmit 25th Line transmitLine25(); break; case '#': // Transmit Page transmitPage(); break; default: debugss(ssH19, WARNING, "Unhandled ESC: %d\n", ch); /// \todo - verify this is how the H19 ROM does it. break; } } else if (mode_m == SetMode) { mode_m = Normal; switch (ch) { case '1': // Enable 25th line // From the ROM, it erases line 25 on the enable, but here we erase on the disable. line25_m = true; break; case '2': // No key click keyClick_m = true; break; case '3': // Hold screen mode holdScreen_m = true; break; case '4': // Block Cursor cursorBlock_m = true; updated_m = true; break; case '5': // Cursor Off cursorOff_m = true; updated_m = true; break; case '6': // Keypad Shifted keypadShifted_m = true; break; case '7': // Alternate Keypad mode altKeypadMode_m = true; break; case '8': // Auto LF autoLF_m = true; break; case '9': // Auto CR autoCR_m = true; break; default: /// \todo Need to process ch as if none of this happened... debugss(ssH19, WARNING, "Invalid set Mode: %c\n", ch); break; } } else if (mode_m == ResetMode) { mode_m = Normal; switch (ch) { case '1': // Disable 25th line eraseLine(rowsMain_c); line25_m = false; updated_m = true; break; case '2': // key click keyClick_m = false; break; case '3': // Hold screen mode holdScreen_m = false; break; case '4': // Block Cursor cursorBlock_m = false; updated_m = true; break; case '5': // Cursor On cursorOff_m = false; updated_m = true; break; case '6': // Keypad Unshifted keypadShifted_m = false; break; case '7': // Exit Alternate Keypad mode altKeypadMode_m = false; break; case '8': // No Auto LF autoLF_m = false; break; case '9': // No Auto CR autoCR_m = false; break; default: /// \todo Need to process ch as if none of this happened... debugss(ssH19, WARNING, "Invalid reset Mode: %c\n", ch); break; } } else if (mode_m == DCA_1) { // From actual H19, once the line is specified, the cursor // immediately moves to that line, so no need to save the // position and wait for the entire command. /// \todo verify that this is the same on newer H19s. if (ch == ascii::CAN) { // cancel mode_m = Normal; } else { // \todo handle error conditions int pos = ch - 31; // verify valid Position if (((pos > 0) && (pos < (signed) rows_c)) || ((pos == (signed) rows_c) && (line25_m))) { posY_m = pos - 1; } else { /// \todo check to see how a real h19 handles this. debugss(ssH19, INFO, "DCA invalid Y: %d\n", pos); } mode_m = DCA_2; } } else if (mode_m == DCA_2) { if (ch == ascii::CAN) { // cancel mode_m = Normal; } else { int pos = ch - 31; if ((pos > 0) && (pos < 81)) { posX_m = pos - 1; } else { posX_m = (cols_c - 1); } updated_m = true; mode_m = Normal; } } }
Screen::InputActions Screen::getInput2( void ) { gotoxy( cur_x, cur_y2 ); uint16_t key = bioskey(0); if ( eatNextChar == true ) { eatNextChar = false; return AteOneKeypress; } bool removeColorPopup = false; if ( (key & 0xff) == 0 ) { // If any function key is pressed get rid of the color chart popup table removeColorPopup = true; // Function key uint8_t fkey = key >> 8; switch ( fkey ) { case 19: return ShowRawToggle; // Alt-R case 20: return TimestampToggle; // Alt-T case 31: return Stats; // Alt-S case 35: return Help; // Alt-H case 38: return LoggingToggle; // Alt-L case 45: return EndProgram; // Alt-X case 46: return CloseWindow; // Alt-C case 48: return BeepToggle; // Alt-B case 73: return BackScroll; // PgUp case 81: return ForwardScroll; // PgDn case 71: { // Home cur_x = 0; cur_y = 0; cur_y2 = separatorRow+1; break; } case 72: { // Up if ( cur_y ) { cur_y--; cur_y2--; } else { ERRBEEP( ); } break; } case 75: { // Left if ( !isCursorHome( ) ) { cursorBack( ); } else { ERRBEEP( ); } break; } case 77: { // Right if ( cur_x + (cur_y * screenCols) < input_len ) { cursorForward( ); } else { ERRBEEP( ); } break; } case 79: { // End cur_x = input_len % screenCols; cur_y = input_len / screenCols; cur_y2 = cur_y + separatorRow + 1; break; } case 80: { // Down if ( cur_x + ((cur_y+1)*screenCols) <= input_len ) { cur_y++; cur_y2++; } else { ERRBEEP( ); } break; } case 82: { // Insert insertMode = !insertMode; if ( insertMode ) { sound(500); delay(50); sound(750); delay(50); nosound( ); } else { // Not really complaining - just indicating back to overstrike sound(750); delay(50); sound(500); delay(50); nosound( ); } break; } case 83: { // Delete // Has to be on an existing char uint16_t startIndex = cur_x + cur_y*screenCols; if ( startIndex < input_len ) { memmove( userInputBuffer+startIndex, userInputBuffer+startIndex+1, (input_len-startIndex) ); input_len--; userInputBuffer[input_len] = 0; repaintInputArea( startIndex, userInputBuffer+startIndex, (input_len-startIndex) ); } else { ERRBEEP( ); } break; } case 129: { // Alt-0 (Server Session) *switchToSession = 0; return SwitchSession; } default: { if ( fkey >= 120 && fkey <= 128 ) { *switchToSession = fkey - 119; return SwitchSession; } } } }