# HG changeset patch
# User Stefan Miereis <stefan.miereis@gmx.de>
# Date 1431295667 -7200
#      Mon May 11 00:07:47 2015 +0200
# Node ID 28bc948a4b9f03f91309931be59aa9198f716cd3
# Parent  c0f64bc26eee83ad41e617cf484d3709b224ad58
Added horizontal scroll bar with (almost) infinite scrolling

diff -r c0f64bc26eee -r 28bc948a4b9f libgui/qterminal/libqterminal/unix/Emulation.cpp
--- a/libgui/qterminal/libqterminal/unix/Emulation.cpp	Wed May 06 20:52:16 2015 +0100
+++ b/libgui/qterminal/libqterminal/unix/Emulation.cpp	Mon May 11 00:07:47 2015 +0200
@@ -58,8 +58,8 @@
 {
 
   // create screens with a default size
-  _screen[0] = new Screen(40,80);
-  _screen[1] = new Screen(40,80);
+  _screen[0] = new Screen(40,10000);  //To approximate infinite line lengths, we initialize the screens with 10,000 columns
+  _screen[1] = new Screen(40,10000);
   _currentScreen = _screen[0];
 
   QObject::connect(&_bulkTimer1, SIGNAL(timeout()), this, SLOT(showBulk()) );
diff -r c0f64bc26eee -r 28bc948a4b9f libgui/qterminal/libqterminal/unix/Screen.cpp
--- a/libgui/qterminal/libqterminal/unix/Screen.cpp	Wed May 06 20:52:16 2015 +0100
+++ b/libgui/qterminal/libqterminal/unix/Screen.cpp	Mon May 11 00:07:47 2015 +0200
@@ -67,6 +67,8 @@
 Screen::Screen(int l, int c)
   : lines(l),
     columns(c),
+    maxCharsInLine(1),
+    currentCharsInLine(0),
     screenLines(new ImageLine[lines+1] ),
     _scrolledLines(0),
     _droppedLines(0),
@@ -242,6 +244,7 @@
   if (n == 0) n = 1; // Default
   int p = qMax(0,qMin(cuX+n-1,columns-1));
   clearImage(loc(cuX,cuY),loc(p,cuY),' ');
+  currentCharsInLine = qMax(0, currentCharsInLine - n );
 }
 
 void Screen::deleteChars(int n)
@@ -263,6 +266,7 @@
   Q_ASSERT( cuX+n < screenLines[cuY].count() );
 
   screenLines[cuY].remove(cuX,n);
+  currentCharsInLine = qMax(0, currentCharsInLine - n );
 }
 
 void Screen::insertChars(int n)
@@ -276,6 +280,7 @@
 
   if ( screenLines[cuY].count() > columns )
       screenLines[cuY].resize(columns);
+  currentCharsInLine = qMax( currentCharsInLine, screenLines[cuY].size() );
 }
 
 void Screen::deleteLines(int n)
@@ -509,24 +514,24 @@
 
 */
 
-void Screen::copyFromHistory(Character* dest, int startLine, int count) const
+void Screen::copyFromHistory(Character* dest, int startLine, int count, int startColumn, int width) const
 {
   Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= hist->getLines() );
 
   for (int line = startLine; line < startLine + count; line++)
   {
-    const int length = qMin(columns,hist->getLineLen(line));
-    const int destLineOffset  = (line-startLine)*columns;
+    const int length = qMax(0, qMin(width,hist->getLineLen(line)-startColumn) );
+    const int destLineOffset  = (line-startLine)*width;
 
-    hist->getCells(line,0,length,dest + destLineOffset);
+    hist->getCells(line,startColumn,length,dest + destLineOffset);
 
-    for (int column = length; column < columns; column++)
-		dest[destLineOffset+column] = defaultChar;
+    for (int column = length; column < width; column++)
+        dest[destLineOffset+column] = defaultChar;
 
 	// invert selected text
 	if (sel_begin !=-1)
 	{
-    	for (int column = 0; column < columns; column++)
+          for (int column = startColumn; column < width; column++)
     	{
         	if (isSelected(column,line))
 			{
@@ -537,21 +542,19 @@
   }
 }
 
-void Screen::copyFromScreen(Character* dest , int startLine , int count) const
+void Screen::copyFromScreen(Character* dest , int startLine , int count, int startColumn, int width) const
 {
 	Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= lines );
 
     for (int line = startLine; line < (startLine+count) ; line++)
     {
-       int srcLineStartIndex  = line*columns;
-	   int destLineStartIndex = (line-startLine)*columns;
+       int destLineStartIndex = (line-startLine)*width;
 
-       for (int column = 0; column < columns; column++)
+       for (int column = startColumn; column < startColumn+width; column++)
        {
-		 int srcIndex = srcLineStartIndex + column;
-		 int destIndex = destLineStartIndex + column;
+         int destIndex = destLineStartIndex + column - startColumn;
 
-         dest[destIndex] = screenLines[srcIndex/columns].value(srcIndex%columns,defaultChar);
+         dest[destIndex] = screenLines[line].value(column,defaultChar);
 
 	     // invert selected text
          if (sel_begin != -1 && isSelected(column,line + hist->getLines()))
@@ -561,14 +564,15 @@
     }
 }
 
-void Screen::getImage( Character* dest, int size, int startLine, int endLine ) const
+void Screen::getImage( Character* dest, int size, int startLine, int endLine, int startColumn, int width ) const
 {
   Q_ASSERT( startLine >= 0 );
   Q_ASSERT( endLine >= startLine && endLine < hist->getLines() + lines );
+  Q_ASSERT( startColumn >= 0 && startColumn+width < columns );
 
   const int mergedLines = endLine - startLine + 1;
 
-  Q_ASSERT( size >= mergedLines * columns );
+  Q_ASSERT( size >= mergedLines * width );
   Q_UNUSED( size );
 
   const int linesInHistoryBuffer = qBound(0,hist->getLines()-startLine,mergedLines);
@@ -576,27 +580,29 @@
 
   // copy lines from history buffer
   if (linesInHistoryBuffer > 0) {
-  	copyFromHistory(dest,startLine,linesInHistoryBuffer);
+        copyFromHistory(dest,startLine,linesInHistoryBuffer,startColumn,width);
     }
 
   // copy lines from screen buffer
   if (linesInScreenBuffer > 0) {
-  	copyFromScreen(dest + linesInHistoryBuffer*columns,
-				   startLine + linesInHistoryBuffer - hist->getLines(),
-				   linesInScreenBuffer);
-    }				
+  	copyFromScreen(dest + linesInHistoryBuffer*width,
+                       startLine + linesInHistoryBuffer - hist->getLines(),
+                       linesInScreenBuffer, startColumn, width);
+    }
 
   // invert display when in screen mode
   if (getMode(MODE_Screen))
   {
-    for (int i = 0; i < mergedLines*columns; i++)
+    for (int i = 0; i < mergedLines*width; i++)
       reverseRendition(dest[i]); // for reverse display
   }
 
   // mark the character at the current cursor position
-  int cursorIndex = loc(cuX, cuY + linesInHistoryBuffer);
-  if(getMode(MODE_Cursor) && cursorIndex < columns*mergedLines)
-    dest[cursorIndex].rendition |= RE_CURSOR;
+  int cursorIndex = cuX + (cuY + linesInHistoryBuffer) * width;
+  if (cuX>=startColumn && cuX <startColumn+width) {
+    if(getMode(MODE_Cursor) && cursorIndex < width * mergedLines)
+      dest[cursorIndex-startColumn].rendition |= RE_CURSOR;
+  }
 }
 
 QVector<LineProperty> Screen::getLineProperties( int startLine , int endLine ) const
@@ -638,7 +644,7 @@
 
 void Screen::reset(bool clearScreen)
 {
-    setMode(MODE_Wrap  ); saveMode(MODE_Wrap  );  // wrap at end of margin
+  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
@@ -660,6 +666,7 @@
 
 void Screen::clear()
 {
+  currentCharsInLine=0;
   clearEntireScreen();
   home();
 }
@@ -673,7 +680,10 @@
   if (screenLines[cuY].size() < cuX+1)
           screenLines[cuY].resize(cuX+1);
 
-  if (BS_CLEARS) screenLines[cuY][cuX].character = ' ';
+  if (BS_CLEARS) {
+    screenLines[cuY][cuX].character = ' ';
+    currentCharsInLine = qMax( 0, currentCharsInLine-1 );
+  }
 }
 
 void Screen::Tabulate(int n)
@@ -728,6 +738,8 @@
 
 void Screen::NewLine()
 {
+  maxCharsInLine=qMax( maxCharsInLine, currentCharsInLine );
+  currentCharsInLine=0;
   if (getMode(MODE_NewLine)) Return();
   index();
 }
@@ -769,7 +781,10 @@
     else
       cuX = columns-w;
   }
-
+  if ( cuX+w>getMaxLineLength() ) {
+    currentCharsInLine++;
+    maxCharsInLine++;
+  }
   // ensure current line vector has enough elements
   int size = screenLines[cuY].size();
   if (size == 0 && cuY > 0)
@@ -781,6 +796,7 @@
     if (size < cuX+w)
     {
           screenLines[cuY].resize(cuX+w);
+          currentCharsInLine = qMax(currentCharsInLine,screenLines[cuY].size());
     }
   }
 
@@ -1132,6 +1148,7 @@
 
 void Screen::clearToEndOfLine()
 {
+  currentCharsInLine = qMax(cuX, maxCharsInLine);
   clearImage(loc(cuX,cuY),loc(columns-1,cuY),' ');
 }
 
@@ -1142,6 +1159,7 @@
 
 void Screen::clearEntireLine()
 {
+  currentCharsInLine = 0;
   clearImage(loc(0,cuY),loc(columns-1,cuY),' ');
 }
 
diff -r c0f64bc26eee -r 28bc948a4b9f libgui/qterminal/libqterminal/unix/Screen.h
--- a/libgui/qterminal/libqterminal/unix/Screen.h	Wed May 06 20:52:16 2015 +0100
+++ b/libgui/qterminal/libqterminal/unix/Screen.h	Mon May 11 00:07:47 2015 +0200
@@ -362,7 +362,7 @@
      * @param startLine Index of first line to copy
      * @param endLine Index of last line to copy
      */
-    void getImage( Character* dest , int size , int startLine , int endLine ) const;
+  void getImage( Character* dest , int size , int startLine , int endLine , int startColumn , int width ) const;
 
     /**
      * Returns the additional attributes associated with lines in the image.
@@ -377,6 +377,16 @@
     int  getLines()   { return lines; }
     /** Return the number of columns. */
     int  getColumns() { return columns; }
+    /** Return the largest number of characters in a line*/
+    int getMaxLineLength() const
+    { return qMax(currentCharsInLine, maxCharsInLine); }
+    /** Returns the length of the current Line */
+    int getLineLength() const
+    {
+      if ( cuY < screenLines->size() )
+	return screenLines[cuY].size();
+      else return 0;
+    }
     /** Return the number of lines in the history buffer. */
     int  getHistLines ();
     /**
@@ -575,16 +585,19 @@
 
 	// copies 'count' lines from the screen buffer into 'dest',
 	// starting from 'startLine', where 0 is the first line in the screen buffer
-	void copyFromScreen(Character* dest, int startLine, int count) const;
+  void copyFromScreen(Character* dest, int startLine, int count, int startColumn, int width) const;
 	// copies 'count' lines from the history buffer into 'dest',
 	// starting from 'startLine', where 0 is the first line in the history
-	void copyFromHistory(Character* dest, int startLine, int count) const;
+  void copyFromHistory(Character* dest, int startLine, int count, int startColumn, int width) const;
 
 
     // screen image ----------------
     int lines;
     int columns;
 
+    int maxCharsInLine;
+    int currentCharsInLine;
+
     typedef QVector<Character> ImageLine;      // [0..columns]
     ImageLine*          screenLines;    // [lines]
 
diff -r c0f64bc26eee -r 28bc948a4b9f libgui/qterminal/libqterminal/unix/ScreenWindow.cpp
--- a/libgui/qterminal/libqterminal/unix/ScreenWindow.cpp	Wed May 06 20:52:16 2015 +0100
+++ b/libgui/qterminal/libqterminal/unix/ScreenWindow.cpp	Mon May 11 00:07:47 2015 +0200
@@ -34,7 +34,9 @@
 	, _windowBufferSize(0)
 	, _bufferNeedsUpdate(true)
 	, _windowLines(1)
+    , _windowColumns(1)
     , _currentLine(0)
+    , _currentColumn(0)
     , _trackOutput(true)
     , _scrollCount(0)
 {
@@ -59,7 +61,7 @@
 Character* ScreenWindow::getImage()
 {
 	// reallocate internal buffer if the window size has changed
-	int size = windowLines() * windowColumns();
+        int size = windowLines() * windowColumns()+1;
 	if (_windowBuffer == 0 || _windowBufferSize != size)
 	{
 		delete[] _windowBuffer;
@@ -72,7 +74,8 @@
 		return _windowBuffer;
 
 	_screen->getImage(_windowBuffer,size,
-					  currentLine(),endWindowLine());
+                          currentLine(),endWindowLine(),
+                          currentColumn(), windowColumns() );
 
 	// this window may look beyond the end of the screen, in which
 	// case there will be an unused area which needs to be filled
@@ -168,10 +171,15 @@
 {
 	return _windowLines;		
 }
+void ScreenWindow::setWindowColumns(int columns)
+{
+  Q_ASSERT(columns > 0);
+  _windowColumns = columns;
+}
 
 int ScreenWindow::windowColumns() const
 {
-    return _screen->getColumns();
+    return _windowColumns;
 }
 
 int ScreenWindow::lineCount() const
@@ -184,6 +192,16 @@
     return _screen->getColumns();
 }
 
+int ScreenWindow::maxLineLength() const
+{
+  return _screen->getMaxLineLength();
+}
+
+int ScreenWindow::lineLength() const
+{
+  return _screen->getLineLength();
+}
+
 QPoint ScreenWindow::cursorPosition() const
 {
     QPoint position;
@@ -199,6 +217,11 @@
     return qBound(0,_currentLine,lineCount()-windowLines());
 }
 
+int ScreenWindow::currentColumn() const
+{
+  return qBound(0, _currentColumn,columnCount()-windowColumns());
+}
+
 void ScreenWindow::scrollBy( RelativeScrollMode mode , int amount )
 {
     if ( mode == ScrollLines )
@@ -211,6 +234,11 @@
     }
 }
 
+void ScreenWindow::hscrollBy( int amount )
+{
+  hscrollTo( currentColumn() + amount );
+}
+
 bool ScreenWindow::atEndOfOutput() const
 {
     return currentLine() == (lineCount()-windowLines());
@@ -233,6 +261,16 @@
     emit scrolled(_currentLine);
 }
 
+void ScreenWindow::hscrollTo( int column )
+{
+  int maxCurrentColumnNumber = maxLineLength() - _windowColumns+2; //add 2 to ensure that the cursor is visible at the end of the line
+  column = qBound(0, column, maxCurrentColumnNumber);
+  _currentColumn = column;
+
+  _bufferNeedsUpdate = true;
+  emit hscrolled(_currentColumn);
+}
+
 void ScreenWindow::setTrackOutput(bool trackOutput)
 {
     _trackOutput = trackOutput;
diff -r c0f64bc26eee -r 28bc948a4b9f libgui/qterminal/libqterminal/unix/ScreenWindow.h
--- a/libgui/qterminal/libqterminal/unix/ScreenWindow.h	Wed May 06 20:52:16 2015 +0100
+++ b/libgui/qterminal/libqterminal/unix/ScreenWindow.h	Mon May 11 00:07:47 2015 +0200
@@ -143,6 +143,8 @@
 	void setWindowLines(int lines);
     /** Returns the number of lines in the window */
     int windowLines() const;
+    /** Sets the number of columns in the window */
+    void setWindowColumns(int columns);
     /** Returns the number of columns in the window */
     int windowColumns() const;
 
@@ -150,10 +152,15 @@
     int lineCount() const;
     /** Returns the total number of columns in the screen */
     int columnCount() const;
+    /** Returns the largest number of characters in a line */
+    int maxLineLength() const;
+    /** Returns the number of characters in the line that is currently being edited */
+    int lineLength() const;
 
     /** Returns the index of the line which is currently at the top of this window */
     int currentLine() const;
-
+    /** Returns the index of the column which is currently at the leftmost side of this window */
+    int currentColumn() const;
     /**
      * Returns the position of the cursor
      * within the window.
@@ -169,6 +176,9 @@
     /** Scrolls the window so that @p line is at the top of the window */
     void scrollTo( int line );
 
+    /** Scrolls the window so that @p column is at the left of the window */
+    void hscrollTo( int column );
+
     enum RelativeScrollMode
     {
         ScrollLines,
@@ -187,6 +197,13 @@
     void scrollBy( RelativeScrollMode mode , int amount );
 
     /**
+     * Scrolls the window horizontally relative to its current position.
+     * @param amount The number of columns to scroll by. If this number is positive, the view
+     * is scrolled right, else left.
+     */
+    void hscrollBy(int amount);
+
+    /**
      * Specifies whether the window should automatically move to the bottom
      * of the screen when new output is added.
      *
@@ -228,6 +245,12 @@
      */
     void scrolled(int line);
 
+      /** Emitted when the screen window is scrolled horizontally
+     * @param column The column which is now at the leftmost side of the window
+     */
+    void hscrolled(int column);
+
+
     /**
      * Emitted when the selection is changed.
      */
@@ -243,7 +266,9 @@
 	bool _bufferNeedsUpdate;
 
 	int  _windowLines;
+    int _windowColumns;
     int  _currentLine; // see scrollTo() , currentLine()
+    int _currentColumn; //see hscrollTo()
     bool _trackOutput; // see setTrackOutput() , trackOutput()
     int  _scrollCount; // count of lines which the window has been scrolled by since
                        // the last call to resetScrollCount()
diff -r c0f64bc26eee -r 28bc948a4b9f libgui/qterminal/libqterminal/unix/TerminalModel.cpp
--- a/libgui/qterminal/libqterminal/unix/TerminalModel.cpp	Wed May 06 20:52:16 2015 +0100
+++ b/libgui/qterminal/libqterminal/unix/TerminalModel.cpp	Mon May 11 00:07:47 2015 +0200
@@ -277,7 +277,7 @@
              view->columns() >= VIEW_COLUMNS_THRESHOLD )
         {
             minLines = (minLines == -1) ? view->lines() : qMin( minLines , view->lines() );
-            minColumns = (minColumns == -1) ? view->columns() : qMin( minColumns , view->columns() );
+            minColumns = (minColumns == -1) ? view->screenColumns() : qMin( minColumns , view->screenColumns() );
         }
     }
 
diff -r c0f64bc26eee -r 28bc948a4b9f libgui/qterminal/libqterminal/unix/TerminalView.cpp
--- a/libgui/qterminal/libqterminal/unix/TerminalView.cpp	Wed May 06 20:52:16 2015 +0100
+++ b/libgui/qterminal/libqterminal/unix/TerminalView.cpp	Mon May 11 00:07:47 2015 +0200
@@ -100,6 +100,7 @@
       connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateLineProperties()) );
       connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateImage()) );
       window->setWindowLines(_lines);
+      window->setWindowColumns(_columns);
     }
 }
 
@@ -259,6 +260,7 @@
   ,_preserveLineBreaks(false)
   ,_columnSelectionMode(false)
   ,_scrollbarLocation(NoScrollBar)
+  ,_showHScrollBar(true)
   ,_wordCharacters(":@-./_~")
   ,_bellMode(SystemBeepBell)
   ,_blinking(false)
@@ -296,6 +298,13 @@
   connect(_scrollBar, SIGNAL(valueChanged(int)), this,
           SLOT(scrollBarPositionChanged(int)));
 
+  //create horizontal scroll bar
+  _hscrollBar = new QScrollBar(Qt::Horizontal, this);
+  setHScroll(0, 0);
+  _hscrollBar->setCursor( Qt::ArrowCursor );
+  connect(_hscrollBar, SIGNAL(valueChanged(int)), this,
+          SLOT(hscrollBarPositionChanged(int)));
+
   // setup timers for blinking cursor and text
   _blinkTimer   = new QTimer(this);
   connect(_blinkTimer, SIGNAL(timeout()), this, SLOT(blinkEvent()));
@@ -526,7 +535,13 @@
         rect.intersected(_scrollBar->geometry()) :
         QRect();
 
+  QRect hscrollBarArea = _hscrollBar->isVisible() ?
+    rect.intersected(_hscrollBar->geometry()) :
+    QRect();
+
   QRegion contentsRegion = QRegion(rect).subtracted(scrollBarArea);
+
+  contentsRegion = contentsRegion.subtracted(hscrollBarArea);
   QRect contentsRect = contentsRegion.boundingRect();
 
   painter.fillRect(contentsRect, backgroundColor);
@@ -829,6 +844,7 @@
   int columns = _screenWindow->windowColumns();
 
   setScroll( _screenWindow->currentLine() , _screenWindow->lineCount() );
+  setHScroll( _screenWindow->currentColumn(), _screenWindow->maxLineLength() );
 
   if (!_image)
     updateImageSize(); // Create _image
@@ -1099,6 +1115,14 @@
     return QPoint(0,0);
 }
 
+int TerminalView::screenColumns() const
+{
+  if (_screenWindow)
+    return _screenWindow->columnCount();
+  else
+    return _columns;
+}
+
 QRect TerminalView::preeditRect() const
 {
   const int preeditLength = string_width(_inputMethodData.preeditString);
@@ -1388,6 +1412,7 @@
 
   QRect cursorRect = imageToWidget( QRect(cursorPosition(),QSize(1,1)) );
 
+  cursorRect.translate( -_screenWindow->currentColumn()*_fontWidth, 0);
   update(cursorRect);
 }
 
@@ -1443,7 +1468,10 @@
 
   //qDebug("%s %d updateImageSize", __FILE__, __LINE__);
   if (_screenWindow)
-    _screenWindow->setWindowLines(_lines);
+    {
+      _screenWindow->setWindowLines(_lines);
+      _screenWindow->setWindowColumns(_columns);
+    }
 
   _resizing = (oldlin!=_lines) || (oldcol!=_columns);
 
@@ -1499,6 +1527,14 @@
   updateImage();
 }
 
+void TerminalView::hscrollBarPositionChanged(int)
+{
+  if (!_screenWindow)
+    return;
+  _screenWindow->hscrollTo( _hscrollBar->value() );
+  updateImage();
+}
+
 void TerminalView::setScroll(int cursor, int slines)
 {
   //qDebug("%s %d setScroll", __FILE__, __LINE__);
@@ -1522,6 +1558,22 @@
   connect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int)));
 }
 
+void TerminalView::setHScroll(int cursor, int scolumns)
+{
+  if ( _hscrollBar->minimum() == 0 &&
+       _hscrollBar->maximum() == (scolumns-_columns) &&
+       _hscrollBar->value() == cursor)
+    {
+      return;
+    }
+  disconnect(_hscrollBar, SIGNAL(valueChanged(int)), this, SLOT(hscrollBarPositionChanged(int)));
+  _hscrollBar->setRange(0,scolumns - _columns);
+  _hscrollBar->setSingleStep(1);
+  _hscrollBar->setPageStep(_columns);
+  _hscrollBar->setValue(cursor);
+  connect(_hscrollBar, SIGNAL(valueChanged(int)),this, SLOT(hscrollBarPositionChanged(int)));
+}
+
 void TerminalView::setScrollBarPosition(ScrollBarPosition position)
 {
   if (_scrollbarLocation == position) {
@@ -1540,6 +1592,18 @@
   update();
 }
 
+void TerminalView::setHScrollBar(bool show)
+{
+  if ( !show )
+    _hscrollBar->hide();
+  else
+    _hscrollBar->show();
+  _topMargin = _leftMargin = 1;
+  _showHScrollBar = show;
+  propagateSize();
+  update();
+}
+
 void TerminalView::mousePressEvent(QMouseEvent* ev)
 {
   if ( _possibleTripleClick && (ev->button()==Qt::LeftButton) ) {
@@ -1638,7 +1702,7 @@
   int charColumn = 0;
 
   getCharacterPosition(ev->pos(),charLine,charColumn);
-
+  charColumn = charColumn+_screenWindow->currentColumn();
   // handle filters
   // change link hot-spot appearance on mouse-over
   Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn);
@@ -1926,9 +1990,9 @@
 
   if (_actSel < 2 || swapping) {
       if (_columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode) {
-          _screenWindow->setSelectionStart(ohere.x(), ohere.y(), true);
+        _screenWindow->setSelectionStart(ohere.x()+_screenWindow->currentColumn(), ohere.y(), true);
         } else {
-          _screenWindow->setSelectionStart(ohere.x() - 1 - offset , ohere.y(), false);
+        _screenWindow->setSelectionStart(ohere.x() - 1 - offset+_screenWindow->currentColumn() , ohere.y(), false);
         }
 
     }
@@ -1938,9 +2002,9 @@
   _pntSel.ry() += _scrollBar->value();
 
   if (_columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode) {
-      _screenWindow->setSelectionEnd(here.x(), here.y());
+    _screenWindow->setSelectionEnd(here.x()+_screenWindow->currentColumn(), here.y());
     } else {
-      _screenWindow->setSelectionEnd(here.x() + offset, here.y());
+    _screenWindow->setSelectionEnd(here.x() + offset+_screenWindow->currentColumn(), here.y());
     }
 }
 
@@ -1952,7 +2016,7 @@
   int charLine;
   int charColumn;
   getCharacterPosition(ev->pos(),charLine,charColumn);
-
+  charColumn = charColumn+_screenWindow->currentColumn();
   if ( ev->button() == Qt::LeftButton)
     {
       emit isBusySelecting(false);
@@ -2330,6 +2394,14 @@
 
   bool emitKeyPressSignal = true;
 
+  if ( !event->text().isEmpty() && cursorPosition().x() >= _screenWindow->currentColumn() + _columns - 1 )
+    {
+      if (cursorPosition().x() >= _screenWindow->maxLineLength())
+        setHScroll(_screenWindow->currentColumn(), _screenWindow->maxLineLength()+1);
+      _screenWindow->hscrollBy(1);
+      _screenWindow->setTrackOutput( _screenWindow->atEndOfOutput() );
+    }
+
   // Keyboard-based navigation
   if ( event->modifiers() == Qt::ShiftModifier )
     {
@@ -2355,6 +2427,14 @@
           //qDebug("%s %d keydown", __FILE__, __LINE__);
           _screenWindow->scrollBy( ScreenWindow::ScrollLines , 1 );
         }
+      else if (event->key() == Qt::Key_Left )
+        {
+          _screenWindow->hscrollBy( -1 );
+        }
+      else if (event->key() == Qt::Key_Right )
+        {
+          _screenWindow->hscrollBy( 1 );
+        }
       else {
           update = false;
         }
@@ -2376,7 +2456,31 @@
 
   _actSel=0; // Key stroke implies a screen update, so TerminalDisplay won't
   // know where the current selection is.
-
+  if ( event->key() == Qt::Key_Return ||
+       ( !(event->modifiers() == Qt::ShiftModifier) &&
+         cursorPosition().x() < _screenWindow->currentColumn() ) ||
+       ( event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_A ) )
+    {
+      _screenWindow->hscrollTo( 0 );
+    }
+  if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_E )
+    {
+      _screenWindow->hscrollTo( _screenWindow->lineLength()-_columns );
+    }
+  if (event->key() == Qt::Key_Left || event->key() == Qt::Key_Backspace)
+    {
+      if (cursorPosition().x() < _screenWindow->currentColumn()+1)
+        {
+          _screenWindow->hscrollBy( -_screenWindow->windowColumns()/2 );
+        }
+    }
+  if (event->key() == Qt::Key_Right)
+    {
+      if (cursorPosition().x() == _screenWindow->currentColumn()+_columns)
+        {
+          _screenWindow->hscrollBy(1);
+        }
+    }
   if (_hasBlinkingCursor)
     {
       _blinkCursorTimer->start(BLINK_DELAY);
@@ -2502,6 +2606,11 @@
   _topMargin = DEFAULT_TOP_MARGIN;
   _contentHeight = contentsRect().height() - 2 * DEFAULT_TOP_MARGIN + /* mysterious */ 1;
 
+  _hscrollBar->resize(contentsRect().width()-_scrollBar->width(),
+                      QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent));
+  _contentHeight = contentsRect().height() - _hscrollBar->height();
+  _hscrollBar->move(contentsRect().bottomLeft() - QPoint(0, _hscrollBar->height()));
+
   if (!_isFixedSize)
     {
       // ensure that display is always at least one column wide
diff -r c0f64bc26eee -r 28bc948a4b9f libgui/qterminal/libqterminal/unix/TerminalView.h
--- a/libgui/qterminal/libqterminal/unix/TerminalView.h	Wed May 06 20:52:16 2015 +0100
+++ b/libgui/qterminal/libqterminal/unix/TerminalView.h	Mon May 11 00:07:47 2015 +0200
@@ -104,13 +104,23 @@
     void setScrollBarPosition(ScrollBarPosition position);
 
     /**
+     * Specifies whether the terminal display has a horizontal scroll bar
+     */
+    void setHScrollBar(bool show);
+    /**
      * Sets the current position and range of the display's scroll bar.
      *
      * @param cursor The position of the scroll bar's thumb.
      * @param lines The maximum value of the scroll bar.
      */
     void setScroll(int cursor, int lines);
-
+    /**
+     * Sets the current position and range of the display's horizontal
+     *  scroll bar.
+     * @param cursor The position of the scroll bar's thumb.
+     * @param columns The maximum value of the scroll bar.
+     */
+    void setHScroll(int cursor, int columns);
     /**
      * Returns the display's filter chain.  When the image for the display is updated,
      * the text is passed through each filter in the chain.  Each filter can define
@@ -249,6 +259,8 @@
      */
     int  columns() { return _columns; }
 
+    /** Returns the number of columns in the screen*/
+    int screenColumns() const;
     /**
      * Returns the height of the characters in the font used to draw the text in the display.
      */
@@ -536,6 +548,7 @@
 protected slots:
 
     void scrollBarPositionChanged(int value);
+    void hscrollBarPositionChanged(int value);
     void blinkEvent();
     void blinkCursorEvent();
 
@@ -673,7 +686,9 @@
 
     QClipboard*  _clipboard;
     QScrollBar* _scrollBar;
+    QScrollBar* _hscrollBar;
     ScrollBarPosition _scrollbarLocation;
+    bool _showHScrollBar;
     QString     _wordCharacters;
     int         _bellMode;
 
