-rw-r--r-- | core/apps/embeddedkonsole/TEScreen.cpp | 60 | ||||
-rw-r--r-- | core/apps/embeddedkonsole/TEWidget.cpp | 63 |
2 files changed, 3 insertions, 120 deletions
diff --git a/core/apps/embeddedkonsole/TEScreen.cpp b/core/apps/embeddedkonsole/TEScreen.cpp index 50807d3..a6cf6a1 100644 --- a/core/apps/embeddedkonsole/TEScreen.cpp +++ b/core/apps/embeddedkonsole/TEScreen.cpp @@ -168,827 +168,769 @@ void TEScreen::cursorRight(int n) /*! Set top and bottom margin. */ void TEScreen::setMargins(int top, int bot) //=STBM { if (top == 0) top = 1; // Default if (bot == 0) bot = lines; // Default top = top - 1; // Adjust to internal lineno bot = bot - 1; // Adjust to internal lineno if ( !( 0 <= top && top < bot && bot < lines ) ) { fprintf(stderr,"%s(%d) : setRegion(%d,%d) : bad range.\n", __FILE__,__LINE__,top,bot); return; // Default error action: ignore } tmargin = top; bmargin = bot; cuX = 0; cuY = getMode(MODE_Origin) ? top : 0; } /*! Move the cursor down one line. If cursor is on bottom margin, the region between the actual top and bottom margin is scrolled up instead. */ void TEScreen::index() //=IND { if (cuY == bmargin) { if (tmargin == 0 && bmargin == lines-1) addHistLine(); // hist.history scrollUp(tmargin,1); } else if (cuY < lines-1) cuY += 1; } /*! Move the cursor up one line. If cursor is on the top margin, the region between the actual top and bottom margin is scrolled down instead. */ void TEScreen::reverseIndex() //=RI { if (cuY == tmargin) scrollDown(tmargin,1); else if (cuY > 0) cuY -= 1; } /*! Move the cursor to the begin of the next line. If cursor is on bottom margin, the region between the actual top and bottom margin is scrolled up. */ void TEScreen::NextLine() //=NEL { Return(); index(); } // Line Editing ---------------------------------------------------------------- /*! \section inserting / deleting characters */ /*! erase `n' characters starting from (including) the cursor position. The line is filled in from the right with spaces. */ void TEScreen::eraseChars(int n) { if (n == 0) n = 1; // Default int p = QMAX(0,QMIN(cuX+n-1,columns-1)); clearImage(loc(cuX,cuY),loc(p,cuY),' '); } /*! delete `n' characters starting from (including) the cursor position. The line is filled in from the right with spaces. */ void TEScreen::deleteChars(int n) { if (n == 0) n = 1; // Default int p = QMAX(0,QMIN(cuX+n,columns-1)); moveImage(loc(cuX,cuY),loc(p,cuY),loc(columns-1,cuY)); clearImage(loc(columns-n,cuY),loc(columns-1,cuY),' '); } /*! insert `n' spaces at the cursor position. The cursor is not moved by the operation. */ void TEScreen::insertChars(int n) { if (n == 0) n = 1; // Default int p = QMAX(0,QMIN(columns-1-n,columns-1)); int q = QMAX(0,QMIN(cuX+n,columns-1)); moveImage(loc(q,cuY),loc(cuX,cuY),loc(p,cuY)); clearImage(loc(cuX,cuY),loc(q-1,cuY),' '); } /*! delete `n' lines starting from (including) the cursor position. The cursor is not moved by the operation. */ void TEScreen::deleteLines(int n) { if (n == 0) n = 1; // Default scrollUp(cuY,n); } /*! insert `n' lines at the cursor position. The cursor is not moved by the operation. */ void TEScreen::insertLines(int n) { if (n == 0) n = 1; // Default scrollDown(cuY,n); } // Mode Operations ----------------------------------------------------------- /*! Set a specific mode. */ void TEScreen::setMode(int m) { currParm.mode[m] = TRUE; switch(m) { case MODE_Origin : cuX = 0; cuY = tmargin; break; //FIXME: home } } /*! Reset a specific mode. */ void TEScreen::resetMode(int m) { currParm.mode[m] = FALSE; switch(m) { case MODE_Origin : cuX = 0; cuY = 0; break; //FIXME: home } } /*! Save a specific mode. */ void TEScreen::saveMode(int m) { saveParm.mode[m] = currParm.mode[m]; } /*! Restore a specific mode. */ void TEScreen::restoreMode(int m) { currParm.mode[m] = saveParm.mode[m]; } //NOTE: this is a helper function /*! Return the setting a specific mode. */ BOOL TEScreen::getMode(int m) { return currParm.mode[m]; } /*! Save the cursor position and the rendition attribute settings. */ void TEScreen::saveCursor() { sa_cuX = cuX; sa_cuY = cuY; sa_cu_re = cu_re; sa_cu_fg = cu_fg; sa_cu_bg = cu_bg; } /*! Restore the cursor position and the rendition attribute settings. */ void TEScreen::restoreCursor() { cuX = QMIN(sa_cuX,columns-1); cuY = QMIN(sa_cuY,lines-1); cu_re = sa_cu_re; cu_fg = sa_cu_fg; cu_bg = sa_cu_bg; effectiveRendition(); } /* ------------------------------------------------------------------------- */ /* */ /* Screen Operations */ /* */ /* ------------------------------------------------------------------------- */ /*! Assing a new size to the screen. The topmost left position is maintained, while lower lines or right hand side columns might be removed or filled with spaces to fit the new size. The region setting is reset to the whole screen and the tab positions reinitialized. */ void TEScreen::resizeImage(int new_lines, int new_columns) { if (cuY > new_lines-1) { // attempt to preserve focus and lines bmargin = lines-1; //FIXME: margin lost for (int i = 0; i < cuY-(new_lines-1); i++) { addHistLine(); scrollUp(horzCursor,1); } } // make new image ca* newimg = (ca*)malloc( new_lines * new_columns * sizeof( ca)); clearSelection(); // clear new image for (int y = 0; y < new_lines; y++) for (int x = 0; x < new_columns; x++) { newimg[y*new_columns+x].c = ' '; newimg[y*new_columns+x].f = DEFAULT_FORE_COLOR; newimg[y*new_columns+x].b = DEFAULT_BACK_COLOR; newimg[y*new_columns+x].r = DEFAULT_RENDITION; } int cpy_lines = QMIN(new_lines, lines); int cpy_columns = QMIN(new_columns,columns); // copy to new image for (int y = 0; y < cpy_lines; y++) for (int x = 0; x < cpy_columns; x++) { newimg[y*new_columns+x].c = image[loc(x,y)].c; newimg[y*new_columns+x].f = image[loc(x,y)].f; newimg[y*new_columns+x].b = image[loc(x,y)].b; newimg[y*new_columns+x].r = image[loc(x,y)].r; } free(image); image = newimg; lines = new_lines; columns = new_columns; cuX = QMIN(cuX,columns-1); cuY = QMIN(cuY,lines-1); // FIXME: try to keep values, evtl. tmargin=0; bmargin=lines-1; initTabStops(); clearSelection(); } /* Clarifying rendition here and in TEWidget. currently, TEWidget's color table is 0 1 2 .. 9 10 .. 17 dft_fg, dft_bg, dim 0..7, intensive 0..7 cu_fg, cu_bg contain values 0..8; - 0 = default color - 1..8 = ansi specified color re_fg, re_bg contain values 0..17 due to the TEWidget's color table rendition attributes are attr widget screen -------------- ------ ------ RE_UNDERLINE XX XX affects foreground only RE_BLINK XX XX affects foreground only RE_BOLD XX XX affects foreground only RE_REVERSE -- XX RE_TRANSPARENT XX -- affects background only RE_INTENSIVE XX -- affects foreground only Note that RE_BOLD is used in both widget and screen rendition. Since xterm/vt102 is to poor to distinguish between bold (which is a font attribute) and intensive (which is a color attribute), we translate this and RE_BOLD in falls eventually appart into RE_BOLD and RE_INTENSIVE. */ void TEScreen::reverseRendition(ca* p) { UINT8 f = p->f; UINT8 b = p->b; p->f = b; p->b = f; //p->r &= ~RE_TRANSPARENT; } void TEScreen::effectiveRendition() // calculate rendition { ef_re = cu_re & (RE_UNDERLINE | RE_BLINK); if (cu_re & RE_REVERSE) { ef_fg = cu_bg; ef_bg = cu_fg; } else { ef_fg = cu_fg; ef_bg = cu_bg; } if (cu_re & RE_BOLD) { if (ef_fg < BASE_COLORS) ef_fg += BASE_COLORS; else ef_fg -= BASE_COLORS; } } /*! returns the image. Get the size of the image by \sa getLines and \sa getColumns. NOTE that the image returned by this function must later be freed. */ ca* TEScreen::getCookedImage() { int x,y; ca* merged = (ca*)malloc(lines*columns*sizeof(ca)); ca dft(' ',DEFAULT_FORE_COLOR,DEFAULT_BACK_COLOR,DEFAULT_RENDITION); for (y = 0; (y < lines) && (y < (hist.getLines()-histCursor)); y++) { int len = QMIN(columns,hist.getLineLen(y+histCursor)); int yp = y*columns; int yq = (y+histCursor)*columns; hist.getCells(y+histCursor,0,len,merged+yp); for (x = len; x < columns; x++) merged[yp+x] = dft; for (x = 0; x < columns; x++) { int p=x + yp; int q=x + yq; if ( ( q >= sel_TL ) && ( q <= sel_BR ) ) reverseRendition(&merged[p]); // for selection } } if (lines >= hist.getLines()-histCursor) { for (y = (hist.getLines()-histCursor); y < lines ; y++) { int yp = y*columns; int yq = (y+histCursor)*columns; int yr = (y-hist.getLines()+histCursor)*columns; for (x = 0; x < columns; x++) { int p = x + yp; int q = x + yq; int r = x + yr; merged[p] = image[r]; if ( q >= sel_TL && q <= sel_BR ) reverseRendition(&merged[p]); // for selection } } } // evtl. inverse display if (getMode(MODE_Screen)) { int i,n = lines*columns; for (i = 0; i < n; i++) reverseRendition(&merged[i]); // for reverse display } if (getMode(MODE_Cursor) && (cuY+(hist.getLines()-histCursor) < lines)) // cursor visible reverseRendition(&merged[loc(cuX,cuY+(hist.getLines()-histCursor))]); return merged; - - /* - int x, y, z; - - ca* merged = (ca*)malloc( lines * columns * sizeof( ca)); - - ca dft(' ',DEFAULT_FORE_COLOR,DEFAULT_BACK_COLOR,DEFAULT_RENDITION); - -// qDebug("hist lines %d, historyCursor %d, minus %d ,lines %d, columns %d", -// hist.getLines(), histCursor, hist.getLines() - histCursor , lines, columns); - for (y = 0; (y < lines) && (y < ( hist.getLines() - histCursor )); y++) { - - int len = QMIN( columns, hist.getLineLen( y + histCursor) ); - int yp = y * columns; - int yq = ( y + histCursor) * columns; -// qDebug("horzCursor %d, columns %d, len %d", horzCursor, columns, len); -// qDebug("lineno %d, colno %d, count %d\n", y + histCursor, (horzCursor / 2), len ); - qDebug("Y %d", y); - hist.getCells( y + histCursor, (horzCursor / 2), len, merged + yp); - - for (x = len; x < columns; x++) - merged[yp + x] = dft; - for (x = 0; x < columns; x++) { - int p = x + yp; int q = x + yq; - if ( ( q >= sel_TL ) && ( q <= sel_BR ) ) - reverseRendition(&merged[p]); // for selection - } - } - - if (lines >= hist.getLines() - histCursor) { - for (y = ( hist.getLines() - histCursor); y < lines ; y++) { - int z = horzCursor; - int yp = y * columns; - int yq = ( y + histCursor) * columns; - int yr = ( y - hist.getLines() + histCursor) * columns; -// qDebug("y %d, yp %d, yq %d, columns %d, z cursor %d", y, yp, yq, columns, z); - for (x = 0; x < columns; x++) { - int p = x + yp; int q = x + yq; int r = (x + (horzCursor/2) ) + yr; - merged[p] = image[r]; - if ( q >= sel_TL && q <= sel_BR ) - reverseRendition( &merged[p]); // for selection - } - } - } - - -// evtl. inverse display - if (getMode(MODE_Screen)) - { int i, n = lines * columns; - for (i = 0; i < n; i++) - reverseRendition( &merged[i]); // for reverse display - } - if (getMode(MODE_Cursor) && ( cuY + ( hist.getLines() - histCursor) < lines)) // cursor visible - - reverseRendition( &merged[ loc( cuX, cuY + ( hist.getLines() - histCursor))] ); - - return merged; - */ - + } /*! */ void TEScreen::reset() { Config cfg("Konsole"); cfg.setGroup("ScrollBar"); if( !cfg.readBoolEntry("HorzScroll",0) ) setMode(MODE_Wrap ); saveMode(MODE_Wrap ); // wrap at end of margin resetMode(MODE_Origin); saveMode(MODE_Origin); // position refere to [1,1] resetMode(MODE_Insert); saveMode(MODE_Insert); // overstroke setMode(MODE_Cursor); // cursor visible resetMode(MODE_Screen); // screen not inverse resetMode(MODE_NewLine); tmargin=0; bmargin=lines-1; setDefaultRendition(); saveCursor(); clear(); } /*! Clear the entire screen and home the cursor. */ void TEScreen::clear() { clearEntireScreen(); home(); } /*! Moves the cursor left one column. */ void TEScreen::BackSpace() { cuX = QMAX(0,cuX-1); if (BS_CLEARS) image[loc(cuX,cuY)].c = ' '; } /*! */ void TEScreen::Tabulate() { // note that TAB is a format effector (does not write ' '); cursorRight(1); while(cuX < columns-1 && !tabstops[cuX]) cursorRight(1); } void TEScreen::clearTabStops() { for (int i = 0; i < columns; i++) tabstops[i-1] = FALSE; } void TEScreen::changeTabStop(bool set) { if (cuX >= columns) return; tabstops[cuX] = set; } void TEScreen::initTabStops() { if (tabstops) free(tabstops); tabstops = (bool*)malloc(columns*sizeof(bool)); // Arrg! The 1st tabstop has to be one longer than the other. // i.e. the kids start counting from 0 instead of 1. // Other programs might behave correctly. Be aware. for (int i = 0; i < columns; i++) tabstops[i] = (i%8 == 0 && i != 0); } /*! This behaves either as IND (Screen::Index) or as NEL (Screen::NextLine) depending on the NewLine Mode (LNM). This mode also affects the key sequence returned for newline ([CR]LF). */ void TEScreen::NewLine() { if (getMode(MODE_NewLine)) Return(); index(); } /*! put `c' literally onto the screen at the current cursor position. VT100 uses the convention to produce an automatic newline (am) with the *first* character that would fall onto the next line (xenl). */ void TEScreen::checkSelection(int from, int to) { if (sel_begin == -1) return; int scr_TL = loc(0, hist.getLines()); //Clear entire selection if it overlaps region [from, to] if ( (sel_BR > (from+scr_TL) )&&(sel_TL < (to+scr_TL)) ) { clearSelection(); } } void TEScreen::ShowCharacter(unsigned short c) { // Note that VT100 does wrapping BEFORE putting the character. // This has impact on the assumption of valid cursor positions. // We indicate the fact that a newline has to be triggered by // putting the cursor one right to the last column of the screen. if (cuX >= columns) { if (getMode(MODE_Wrap)) NextLine(); else cuX = columns - 1; // comment out for no wrap } if (getMode(MODE_Insert)) insertChars(1); int i = loc( cuX, cuY); checkSelection(i, i); // check if selection is still valid. image[i].c = c; image[i].f = ef_fg; image[i].b = ef_bg; image[i].r = ef_re; cuX += 1; } // Region commands ------------------------------------------------------------- /*! scroll up `n' lines within current region. The `n' new lines are cleared. \sa setRegion \sa scrollDown */ void TEScreen::scrollUp(int from, int n) { if (n <= 0 || from + n > bmargin) return; //FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds. moveImage( loc( 0, from), loc( 0, from + n), loc( columns - 1, bmargin)); clearImage( loc( 0, bmargin - n + 1), loc( columns - 1, bmargin), ' '); } /*! scroll down `n' lines within current region. The `n' new lines are cleared. \sa setRegion \sa scrollUp */ void TEScreen::scrollDown(int from, int n) { //FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds. if (n <= 0) return; if (from > bmargin) return; if (from + n > bmargin) n = bmargin - from; moveImage( loc(0,from+n), loc(0,from), loc(columns-1,bmargin-n)); clearImage(loc(0,from),loc(columns-1,from+n-1),' '); } /*! position the cursor to a specific line and column. */ void TEScreen::setCursorYX(int y, int x) { setCursorY(y); setCursorX(x); } /*! Set the cursor to x-th line. */ void TEScreen::setCursorX(int x) { if (x == 0) x = 1; // Default x -= 1; // Adjust cuX = QMAX(0,QMIN(columns-1, x)); } /*! Set the cursor to y-th line. */ void TEScreen::setCursorY(int y) { if (y == 0) y = 1; // Default y -= 1; // Adjust cuY = QMAX(0,QMIN(lines -1, y + (getMode(MODE_Origin) ? tmargin : 0) )); } /*! set cursor to the `left upper' corner of the screen (1,1). */ void TEScreen::home() { cuX = 0; cuY = 0; } /*! set cursor to the begin of the current line. */ void TEScreen::Return() { cuX = 0; } /*! returns the current cursor columns. */ int TEScreen::getCursorX() { return cuX; } /*! returns the current cursor line. */ int TEScreen::getCursorY() { return cuY; } // Erasing --------------------------------------------------------------------- /*! \section Erasing This group of operations erase parts of the screen contents by filling it with spaces colored due to the current rendition settings. Althought the cursor position is involved in most of these operations, it is never modified by them. */ /*! fill screen between (including) `loca' and `loce' with spaces. This is an internal helper functions. The parameter types are internal addresses of within the screen image and make use of the way how the screen matrix is mapped to the image vector. */ void TEScreen::clearImage(int loca, int loce, char c) { int i; int scr_TL=loc(0,hist.getLines()); //FIXME: check positions //Clear entire selection if it overlaps region to be moved... if ( (sel_BR > (loca+scr_TL) )&&(sel_TL < (loce+scr_TL)) ) { clearSelection(); } for (i = loca; i <= loce; i++) { image[i].c = c; image[i].f = ef_fg; //DEFAULT_FORE_COLOR; //FIXME: xterm and linux/ansi image[i].b = ef_bg; //DEFAULT_BACK_COLOR; // many have different image[i].r = ef_re; //DEFAULT_RENDITION; // ideas here. } } /*! move image between (including) `loca' and `loce' to 'dst'. This is an internal helper functions. The parameter types are internal addresses of within the screen image and make use of the way how the screen matrix is mapped to the image vector. */ void TEScreen::moveImage(int dst, int loca, int loce) { //FIXME: check positions if (loce < loca) { // kdDebug() << "WARNING!!! call to TEScreen:moveImage with loce < loca!" << endl; return; } memmove(&image[dst],&image[loca],(loce-loca+1)*sizeof(ca)); } /*! clear from (including) current cursor position to end of screen. */ void TEScreen::clearToEndOfScreen() { clearImage(loc(cuX,cuY),loc(columns-1,lines-1),' '); } /*! clear from begin of screen to (including) current cursor position. */ void TEScreen::clearToBeginOfScreen() { clearImage(loc(0,0),loc(cuX,cuY),' '); } /*! clear the entire screen. */ void TEScreen::clearEntireScreen() { clearImage(loc(0,0),loc(columns-1,lines-1),' '); } /*! fill screen with 'E' This is to aid screen alignment */ void TEScreen::helpAlign() { clearImage(loc(0,0),loc(columns-1,lines-1),'E'); } /*! clear from (including) current cursor position to end of current cursor line. */ void TEScreen::clearToEndOfLine() { clearImage(loc(cuX,cuY),loc(columns-1,cuY),' '); } /*! clear from begin of current cursor line to (including) current cursor position. */ void TEScreen::clearToBeginOfLine() { clearImage(loc(0,cuY),loc(cuX,cuY),' '); } /*! clears entire current cursor line */ void TEScreen::clearEntireLine() { clearImage( loc( 0, cuY),loc( columns - 1, cuY),' '); } // Rendition ------------------------------------------------------------------ /*! set rendition mode */ void TEScreen::setRendition(int re) { cu_re |= re; effectiveRendition(); } /*! reset rendition mode */ void TEScreen::resetRendition(int re) { cu_re &= ~re; effectiveRendition(); } /*! */ void TEScreen::setDefaultRendition() { setForeColorToDefault(); setBackColorToDefault(); cu_re = DEFAULT_RENDITION; effectiveRendition(); } /*! */ void TEScreen::setForeColor(int fgcolor) { cu_fg = (fgcolor&7)+((fgcolor&8) ? 4+8 : 2); effectiveRendition(); } /*! */ void TEScreen::setBackColor(int bgcolor) { diff --git a/core/apps/embeddedkonsole/TEWidget.cpp b/core/apps/embeddedkonsole/TEWidget.cpp index 60021f4..d6ee6e8 100644 --- a/core/apps/embeddedkonsole/TEWidget.cpp +++ b/core/apps/embeddedkonsole/TEWidget.cpp @@ -674,733 +674,674 @@ void TEWidget::mousePressEvent(QMouseEvent* ev) int tLy = tL.y(); word_selection_mode = FALSE; //printf("press top left [%d,%d] by=%d\n",tLx,tLy, bY); if ( ev->button() == LeftButton) { QPoint pos = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h); if ( ev->state() & ControlButton ) preserve_line_breaks = FALSE ; if (mouse_marks || (ev->state() & ShiftButton)) { emit clearSelectionSignal(); iPntSel = pntSel = pos; actSel = 1; // left mouse button pressed but nothing selected yet. grabMouse( /*crossCursor*/ ); // handle with care! } else { emit mouseSignal( 0, pos.x() + 1, pos.y() + 1 ); // left button } } if ( ev->button() == MidButton ) { emitSelection(); } if ( ev->button() == RightButton ) // Configure { emit configureRequest( this, ev->state()&(ShiftButton|ControlButton), ev->x(), ev->y() ); } } void TEWidget::mouseMoveEvent(QMouseEvent* ev) { // for auto-hiding the cursor, we need mouseTracking if (ev->state() == NoButton ) return; if (actSel == 0) return; // don't extend selection while pasting if (ev->state() & MidButton) return; //if ( !contentsRect().contains(ev->pos()) ) return; QPoint tL = contentsRect().topLeft(); int tLx = tL.x(); int tLy = tL.y(); int scroll = scrollbar->value(); // int hScroll = hScrollbar->value(); // we're in the process of moving the mouse with the left button pressed // the mouse cursor will kept catched within the bounds of the text in // this widget. // Adjust position within text area bounds. See FIXME above. QPoint pos = ev->pos(); if ( pos.x() < tLx+blX ) pos.setX( tLx+blX ); if ( pos.x() > tLx+blX+columns*font_w-1 ) pos.setX( tLx+blX+columns*font_w ); if ( pos.y() < tLy+bY ) pos.setY( tLy+bY ); if ( pos.y() > tLy+bY+lines*font_h-1 ) pos.setY( tLy+bY+lines*font_h-1 ); // check if we produce a mouse move event by this if ( pos != ev->pos() ) cursor().setPos(mapToGlobal(pos)); if ( pos.y() == tLy+bY+lines*font_h-1 ) { scrollbar->setValue(scrollbar->value()+yMouseScroll); // scrollforward } if ( pos.y() == tLy+bY ) { scrollbar->setValue(scrollbar->value()-yMouseScroll); // scrollback } QPoint here = QPoint((pos.x()-tLx-blX)/font_w,(pos.y()-tLy-bY)/font_h); QPoint ohere; bool swapping = FALSE; if ( word_selection_mode ) { // Extend to word boundaries int i; int selClass; bool left_not_right = ( here.y() < iPntSel.y() || here.y() == iPntSel.y() && here.x() < iPntSel.x() ); bool old_left_not_right = ( pntSel.y() < iPntSel.y() || pntSel.y() == iPntSel.y() && pntSel.x() < iPntSel.x() ); swapping = left_not_right != old_left_not_right; // Find left (left_not_right ? from here : from start) QPoint left = left_not_right ? here : iPntSel; i = loc(left.x(),left.y()); selClass = charClass(image[i].c); while ( left.x() > 0 && charClass(image[i-1].c) == selClass ) { i--; left.rx()--; } // Find left (left_not_right ? from start : from here) QPoint right = left_not_right ? iPntSel : here; i = loc(right.x(),right.y()); selClass = charClass(image[i].c); while ( right.x() < columns-1 && charClass(image[i+1].c) == selClass ) { i++; right.rx()++; } // Pick which is start (ohere) and which is extension (here) if ( left_not_right ) { here = left; ohere = right; } else { here = right; ohere = left; } } if (here == pntSel && scroll == scrollbar->value()) return; // not moved if ( word_selection_mode ) { if ( actSel < 2 || swapping ) { emit beginSelectionSignal( ohere.x(), ohere.y() ); } } else if ( actSel < 2 ) { emit beginSelectionSignal( pntSel.x(), pntSel.y() ); } actSel = 2; // within selection pntSel = here; emit extendSelectionSignal( here.x(), here.y() ); } void TEWidget::mouseReleaseEvent(QMouseEvent* ev) { //printf("release [%d,%d] %d\n",ev->x()/font_w,ev->y()/font_h,ev->button()); if ( ev->button() == LeftButton) { if ( actSel > 1 ) emit endSelectionSignal(preserve_line_breaks); preserve_line_breaks = TRUE; actSel = 0; //FIXME: emits a release event even if the mouse is // outside the range. The procedure used in `mouseMoveEvent' // applies here, too. QPoint tL = contentsRect().topLeft(); int tLx = tL.x(); int tLy = tL.y(); if (!mouse_marks && !(ev->state() & ShiftButton)) emit mouseSignal( 3, // release (ev->x()-tLx-blX)/font_w + 1, (ev->y()-tLy-bY)/font_h + 1 ); releaseMouse(); } } void TEWidget::mouseDoubleClickEvent(QMouseEvent* ev) { if ( ev->button() != LeftButton) return; QPoint tL = contentsRect().topLeft(); int tLx = tL.x(); int tLy = tL.y(); QPoint pos = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h); // pass on double click as two clicks. if (!mouse_marks && !(ev->state() & ShiftButton)) { emit mouseSignal( 0, pos.x()+1, pos.y()+1 ); // left button emit mouseSignal( 3, pos.x()+1, pos.y()+1 ); // release emit mouseSignal( 0, pos.x()+1, pos.y()+1 ); // left button return; } emit clearSelectionSignal(); QPoint bgnSel = pos; QPoint endSel = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h); int i = loc(bgnSel.x(),bgnSel.y()); iPntSel = bgnSel; word_selection_mode = TRUE; // find word boundaries... int selClass = charClass(image[i].c); { // set the start... int x = bgnSel.x(); while ( x > 0 && charClass(image[i-1].c) == selClass ) { i--; x--; } bgnSel.setX(x); emit beginSelectionSignal( bgnSel.x(), bgnSel.y() ); // set the end... i = loc( endSel.x(), endSel.y() ); x = endSel.x(); while( x < columns-1 && charClass(image[i+1].c) == selClass ) { i++; x++ ; } endSel.setX(x); actSel = 2; // within selection emit extendSelectionSignal( endSel.x(), endSel.y() ); emit endSelectionSignal(preserve_line_breaks); preserve_line_breaks = TRUE; } } void TEWidget::focusInEvent( QFocusEvent * ) { // do nothing, to prevent repainting } void TEWidget::focusOutEvent( QFocusEvent * ) { // do nothing, to prevent repainting } bool TEWidget::focusNextPrevChild( bool next ) { if (next) return false; // This disables changing the active part in konqueror // when pressing Tab return QFrame::focusNextPrevChild( next ); } int TEWidget::charClass(char ch) const { // This might seem like overkill, but imagine if ch was a Unicode // character (Qt 2.0 QChar) - it might then be sensible to separate // the different language ranges, etc. if ( isspace(ch) ) return ' '; static const char *word_characters = ":@-./_~"; if ( isalnum(ch) || strchr(word_characters, ch) ) return 'a'; // Everything else is weird return 1; } void TEWidget::setMouseMarks(bool on) { mouse_marks = on; setCursor( mouse_marks ? ibeamCursor : arrowCursor ); } /* ------------------------------------------------------------------------- */ /* */ /* Clipboard */ /* */ /* ------------------------------------------------------------------------- */ #undef KeyPress void TEWidget::emitSelection() // Paste Clipboard by simulating keypress events { #ifndef QT_NO_CLIPBOARD QString text = QApplication::clipboard()->text(); if ( ! text.isNull() ) { text.replace(QRegExp("\n"), "\r"); QKeyEvent e(QEvent::KeyPress, 0, -1, 0, text); emit keyPressedSignal(&e); // expose as a big fat keypress event emit clearSelectionSignal(); } #endif } void TEWidget::emitText(QString text) { QKeyEvent e(QEvent::KeyPress, 0, -1, 0, text); emit keyPressedSignal(&e); // expose as a big fat keypress event } void TEWidget::pasteClipboard( ) { emitSelection(); } void TEWidget::setSelection(const QString& t) { #ifndef QT_NO_CLIPBOARD // Disconnect signal while WE set the clipboard QObject *cb = QApplication::clipboard(); QObject::disconnect( cb, SIGNAL(dataChanged()), this, SLOT(onClearSelection()) ); QApplication::clipboard()->setText(t); QObject::connect( cb, SIGNAL(dataChanged()), this, SLOT(onClearSelection()) ); #endif } void TEWidget::onClearSelection() { emit clearSelectionSignal(); } /* ------------------------------------------------------------------------- */ /* */ /* Keyboard */ /* */ /* ------------------------------------------------------------------------- */ //FIXME: an `eventFilter' has been installed instead of a `keyPressEvent' // due to a bug in `QT' or the ignorance of the author to prevent // repaint events being emitted to the screen whenever one leaves // or reenters the screen to/from another application. // // Troll says one needs to change focusInEvent() and focusOutEvent(), // which would also let you have an in-focus cursor and an out-focus // cursor like xterm does. // for the auto-hide cursor feature, I added empty focusInEvent() and // focusOutEvent() so that update() isn't called. // For auto-hide, we need to get keypress-events, but we only get them when // we have focus. void TEWidget::doScroll(int lines) { scrollbar->setValue(scrollbar->value()+lines); } void TEWidget::doHScroll(int lines) { hScrollbar->setValue( hScrollbar->value()+lines); } bool TEWidget::eventFilter( QObject *obj, QEvent *e ) { if ( (e->type() == QEvent::Accel || e->type() == QEvent::AccelAvailable ) && qApp->focusWidget() == this ) { static_cast<QKeyEvent *>( e )->ignore(); return true; } if ( obj != this /* when embedded */ && obj != parent() /* when standalone */ ) return FALSE; // not us if ( e->type() == QEvent::Wheel) { QApplication::sendEvent(scrollbar, e); } #ifdef FAKE_CTRL_AND_ALT static bool control = FALSE; static bool alt = FALSE; // qDebug(" Has a keyboard with no CTRL and ALT keys, but we fake it:"); bool dele=FALSE; if ( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease ) { QKeyEvent* ke = (QKeyEvent*)e; bool keydown = e->type() == QEvent::KeyPress || ke->isAutoRepeat(); switch (ke->key()) { case Key_F9: // let this be "Control" control = keydown; e = new QKeyEvent(QEvent::KeyPress, Key_Control, 0, ke->state()); dele=TRUE; break; case Key_F13: // let this be "Alt" alt = keydown; e = new QKeyEvent(QEvent::KeyPress, Key_Alt, 0, ke->state()); dele=TRUE; break; default: if ( control ) { int a = toupper(ke->ascii())-64; if ( a >= 0 && a < ' ' ) { e = new QKeyEvent(e->type(), ke->key(), a, ke->state()|ControlButton, QChar(a,0)); dele=TRUE; } } if ( alt ) { e = new QKeyEvent(e->type(), ke->key(), ke->ascii(), ke->state()|AltButton, ke->text()); dele=TRUE; } } } #endif if ( e->type() == QEvent::KeyPress ) { QKeyEvent* ke = (QKeyEvent*)e; actSel=0; // Key stroke implies a screen update, so TEWidget won't // know where the current selection is. -// qDebug("key pressed is 0x%x, state %d",ke->key(), ke->state()); +// qDebug("key pressed is 0x%x, ascii is 0x%x, state %d", ke->key(), ke->ascii(), ke->state()); if( ke->state() == ShiftButton && ke->key() == Key_Tab) { //lets hardcode this sucker -// qDebug("key pressed 2 is 0x%x",ke->key()); +// qDebug("key pressed 2 is 0x%x", ke->key()); emitText("\\"); // expose } else if( ke->state() == ControlButton && ke->key() == Key_V) { pasteClipboard(); } else emit keyPressedSignal(ke); // expose ke->accept(); #ifdef FAKE_CTRL_AND_ALT if ( dele ) delete e; #endif return true; // stop the event } if ( e->type() == QEvent::Enter ) { QObject::disconnect( (QObject*)cb, SIGNAL(dataChanged()), this, SLOT(onClearSelection()) ); } if ( e->type() == QEvent::Leave ) { QObject::connect( (QObject*)cb, SIGNAL(dataChanged()), this, SLOT(onClearSelection()) ); } return QFrame::eventFilter( obj, e ); } /* ------------------------------------------------------------------------- */ /* */ /* Frame */ /* */ /* ------------------------------------------------------------------------- */ void TEWidget::frameChanged() { propagateSize(); update(); } /* ------------------------------------------------------------------------- */ /* */ /* Sound */ /* */ /* ------------------------------------------------------------------------- */ void TEWidget::Bell() { //#ifdef QT_QWS_CUSTOM //# ifndef QT_NO_COP QCopEnvelope( "QPE/TaskBar", "soundAlarm()" ); //# endif //#else //# ifndef QT_NO_SOUND // QSound::play(Resource::findSound("alarm")); //# endif //#endif // QApplication::beep(); } /* ------------------------------------------------------------------------- */ /* */ /* Auxiluary */ /* */ /* ------------------------------------------------------------------------- */ void TEWidget::clearImage() // initialize the image // for internal use only { for (int y = 0; y < lines; y++) for (int x = 0; x < columns; x++) { image[loc(x,y)].c = 0xff; //' '; image[loc(x,y)].f = 0xff; //DEFAULT_FORE_COLOR; image[loc(x,y)].b = 0xff; //DEFAULT_BACK_COLOR; image[loc(x,y)].r = 0xff; //DEFAULT_RENDITION; } } // Create Image /////////////////////////////////////////////////////// void TEWidget::calcGeometry() { int showhscrollbar = 1; int hwidth = 0; int dcolumns; Config cfg("Konsole"); cfg.setGroup("ScrollBar"); useHorzScroll=cfg.readBoolEntry("HorzScroll",0); if(vcolumns == 0) showhscrollbar = 0; if(showhscrollbar == 1) hwidth = QApplication::style().scrollBarExtent().width(); scrollbar->resize(QApplication::style().scrollBarExtent().width(), contentsRect().height() - hwidth); switch(scrollLoc) { case SCRNONE : columns = ( contentsRect().width() - 2 * rimX ) / font_w; dcolumns = columns; if(vcolumns) columns = vcolumns; blX = (contentsRect().width() - (columns*font_w) ) / 2; if(showhscrollbar) blX = -hposition * font_w; brX = blX; scrollbar->hide(); break; case SCRLEFT : columns = ( contentsRect().width() - 2 * rimX - scrollbar->width()) / font_w; dcolumns = columns; if(vcolumns) columns = vcolumns; brX = (contentsRect().width() - (columns*font_w) - scrollbar->width() ) / 2; if(showhscrollbar) brX = -hposition * font_w; blX = brX + scrollbar->width(); scrollbar->move(contentsRect().topLeft()); scrollbar->show(); break; case SCRRIGHT: columns = ( contentsRect().width() - 2 * rimX - scrollbar->width()) / font_w; dcolumns = columns; if(vcolumns) columns = vcolumns; blX = (contentsRect().width() - (columns*font_w) - scrollbar->width() ) / 2; if(showhscrollbar) blX = -hposition * font_w; brX = blX; scrollbar->move(contentsRect().topRight() - QPoint(scrollbar->width()-1,0)); scrollbar->show(); break; } //FIXME: support 'rounding' styles lines = ( contentsRect().height() - 2 * rimY ) / font_h; bY = (contentsRect().height() - (lines *font_h)) / 2; if(showhscrollbar == 1) { hScrollbar->resize(contentsRect().width() - hwidth, hwidth); hScrollbar->setRange(0, vcolumns - dcolumns); QPoint p = contentsRect().bottomLeft(); hScrollbar->move(QPoint(p.x(), p.y() - hwidth)); hScrollbar->show(); } else hScrollbar->hide(); if(showhscrollbar == 1) { lines = lines - (hwidth / font_h) - 1; if(lines < 1) lines = 1; } - - /*//FIXME: set rimX == rimY == 0 when running in full screen mode. - Config cfg("Konsole"); - cfg.setGroup("ScrollBar"); - useHorzScroll=cfg.readBoolEntry("HorzScroll",0); - - scrollbar->resize( QApplication::style().scrollBarExtent().width(), - contentsRect().height()); - qDebug("font_w %d", font_w); - switch(scrollLoc) - { - case SCRNONE : - columns = ( contentsRect().width() - 2 * rimX ) / font_w; - blX = (contentsRect().width() - (columns*font_w) ) / 2; - brX = blX; - scrollbar->hide(); - break; - case SCRLEFT : - columns = ( contentsRect().width() - 2 * rimX - scrollbar->width()) / font_w; - if(useHorzScroll) columns = columns * (font_w/2); - brX = (contentsRect().width() - (columns*font_w) - scrollbar->width() ) / 2; - blX = brX + scrollbar->width(); - scrollbar->move(contentsRect().topLeft()); - scrollbar->show(); - break; - case SCRRIGHT: - columns = ( contentsRect().width() - 2 * rimX - scrollbar->width() ) / font_w; - if(useHorzScroll) columns = columns * (font_w/2); - blX = (contentsRect().width() - (columns*font_w) - scrollbar->width() ) / 2; - if(useHorzScroll) { - brX = blX =2; - } else { - brX=blX; - } - scrollbar->move(contentsRect().topRight() - QPoint(scrollbar->width()-1,0) ); - scrollbar->show(); - break; - } - - if( !scrollbar->isHidden()) - hScrollbar->resize( contentsRect().width()-SCRWIDTH, QApplication::style() - .scrollBarExtent().height()); - else - hScrollbar->resize( contentsRect().width(), QApplication::style() - .scrollBarExtent().height()); - - hScrollbar->move( 0, contentsRect().height() - SCRWIDTH); - - - if(useHorzScroll) { - hScrollbar->show(); - lines = ( (contentsRect().height() - SCRWIDTH) - 2 * rimY ) / font_h; - bY = ((contentsRect().height() - SCRWIDTH) - (lines *font_h)) / 2; - } else { - hScrollbar->hide(); - lines = (contentsRect().height() - 2 * rimY ) / font_h; - bY = (contentsRect().height() - (lines *font_h)) / 2; - } - */ //FIXME: support 'rounding' styles } void TEWidget::makeImage() //FIXME: rename 'calcGeometry? { calcGeometry(); image = (ca*) malloc(lines*columns*sizeof(ca)); clearImage(); } // calculate the needed size QSize TEWidget::calcSize(int cols, int lins) const { int frw = width() - contentsRect().width(); int frh = height() - contentsRect().height(); int scw = (scrollLoc==SCRNONE?0:scrollbar->width()); return QSize( font_w*cols + 2*rimX + frw + scw, font_h*lins + 2*rimY + frh ); } QSize TEWidget::sizeHint() const { return size(); } void TEWidget::styleChange(QStyle &) { propagateSize(); } #ifndef QT_NO_DRAGANDDROP /* --------------------------------------------------------------------- */ /* */ /* Drag & Drop */ /* */ /* --------------------------------------------------------------------- */ void TEWidget::dragEnterEvent(QDragEnterEvent* e) { e->accept(QTextDrag::canDecode(e) || QUriDrag::canDecode(e)); } void TEWidget::dropEvent(QDropEvent* event) { // The current behaviour when url(s) are dropped is // * if there is only ONE url and if it's a LOCAL one, ask for paste or cd // * in all other cases, just paste // (for non-local ones, or for a list of URLs, 'cd' is nonsense) QStrList strlist; int file_count = 0; dropText = ""; bool bPopup = true; if(QUriDrag::decode(event, strlist)) { if (strlist.count()) { for(const char* p = strlist.first(); p; p = strlist.next()) { if(file_count++ > 0) { dropText += " "; bPopup = false; // more than one file, don't popup } /* KURL url(p); if (url.isLocalFile()) { dropText += url.path(); // local URL : remove protocol } else { dropText += url.prettyURL(); bPopup = false; // a non-local file, don't popup } */ } if (bPopup) // m_drop->popup(pos() + event->pos()); m_drop->popup(mapToGlobal(event->pos())); else { if (currentSession) { currentSession->getEmulation()->sendString(dropText.local8Bit()); } // kdDebug() << "Drop:" << dropText.local8Bit() << "\n"; } } } else if(QTextDrag::decode(event, dropText)) { // kdDebug() << "Drop:" << dropText.local8Bit() << "\n"; if (currentSession) { currentSession->getEmulation()->sendString(dropText.local8Bit()); } // Paste it } } #endif void TEWidget::drop_menu_activated(int item) { #ifndef QT_NO_DRAGANDDROP switch (item) { case 0: // paste currentSession->getEmulation()->sendString(dropText.local8Bit()); // KWM::activate((Window)this->winId()); break; case 1: // cd ... currentSession->getEmulation()->sendString("cd "); struct stat statbuf; if ( ::stat( QFile::encodeName( dropText ), &statbuf ) == 0 ) { if ( !S_ISDIR(statbuf.st_mode) ) { /* KURL url; url.setPath( dropText ); dropText = url.directory( true, false ); // remove filename */ } } dropText.replace(QRegExp(" "), "\\ "); // escape spaces currentSession->getEmulation()->sendString(dropText.local8Bit()); currentSession->getEmulation()->sendString("\n"); // KWM::activate((Window)this->winId()); break; } #endif } void TEWidget::setWrapAt(int columns) { vcolumns = columns; propagateSize(); update(); } |