/* ====================================================================
 * Copyright (c) 2003-2006, Martin Hauner
 *                          http://subcommander.tigris.org
 *
 * Subcommander is licensed as described in the file doc/COPYING, which
 * you should have received as part of this distribution.
 * ====================================================================
 */

// sc
#include "TextLineNrWidget.h"
#include "PainterSetup.h"
#include "TextPositionCalculator.h"
#include "ScrollPositionCalculator.h"
#include "ColorId.h"
#include "sublib/Line.h"
#include "sublib/TextModel.h"
#include "sublib/ColorStorage.h"
#include "sublib/NullTextModel.h"

// sys
#include <stdio.h>
#include <algorithm>
#include <assert.h>


static int dashLinePad = 1;
static int borderPad   = 3;

static NullTextModel NullText;



TextLineNrWidget::TextLineNrWidget( QWidget *parent, unsigned long flags, const char *name )
: QWidget( parent, name ), _flags(flags), _ypos(0) 
{
  _lnColumns = 3;

  _lnLeftPad  = borderPad;
  _lnRightPad = borderPad;

  setSizePolicy( QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Expanding) );
  setBackgroundMode( Qt::NoBackground );

  setModel(&NullText);
}


TextLineNrWidget::~TextLineNrWidget()
{
}

void TextLineNrWidget::setModel( TextModel* model )
{
  _model = model;
  sc::Size lines = _model->getLineCnt();

  char buf[16] = "";
  _lnColumns   = sprintf( buf, "%u", lines );

  updateGeometry();
}

void TextLineNrWidget::setFlags( unsigned long flags )
{
  _flags = flags;
}

void TextLineNrWidget::paintEvent( QPaintEvent *e )
{
  QRect pr = e->rect(); 
  
  // Qt/X11 does crash when pr is null
  // todo: why is pr null?
  if( pr.isNull() )
    return;

  PainterSetup ps(this,pr);
  QPainter& pp = ps.getPainter();

  pp.setPen( ColorStorage::getColor(ColorLineNrFg) );
  pp.setBackgroundColor( ColorStorage::getColor(ColorLineNrBg) );

  QFontMetrics m(font());
  TextPositionCalculator tpc( m, pr, 0, _ypos );
  int topLine = tpc.getTopLine();
  int botLine = tpc.getBottomLine();
  int lnDefWidth = sizeHint().width();

  // calc the first line number we have to draw
  // TODO
  // we could optimize this if we would remember the first visible line
  // and then count from there....
  int clnr   = 0;
  int lineNr = clnr;

  for( int y = -_ypos; y < tpc.getLineY(topLine); y += m.height(), clnr++ )
  {
    Line line = _model->getLine( clnr );
    if( ! line.isEmpty() )
    {
      lineNr++;
    }    
  }

  for( int curLine = topLine; curLine <= botLine; curLine++ )
  {
    // clear line background
    pp.eraseRect( 0, tpc.getLineY(curLine), lnDefWidth, tpc.getFontHeight() );

    Line line = _model->getLine( curLine );
    
    if( ! line.isEmpty() )
    {
      // draw right aligned line number
      char lnBuf[32];
      int  lnLength  = sprintf( lnBuf, "%d", ++lineNr );
      int  lnWidth   = m.width( lnBuf, lnLength );

      int textX = 0;
      if( _flags & Right )
      {
        textX = lnDefWidth-lnWidth-_lnRightPad + 1;
      }
      if( _flags & Left )
      {
        textX = lnDefWidth-lnWidth-_lnRightPad-dashLinePad;
      }

      pp.drawText( textX, tpc.getTextY(curLine), lnBuf, lnLength );
    }
  }

  int dashX = 0;
  if( _flags & Right )
  {
    dashX = 0;
  }
  if( _flags & Left )
  {
    dashX = lnDefWidth - 1;
  }
  // draw dash line

  pp.setPen( ColorStorage::getColor(ColorDashBg) );
  pp.drawLine( dashX, pr.y(), dashX, pr.y()+pr.height() );

  pp.setPen( ColorStorage::getColor(ColorDashFg) );
  for( int d = pr.y()+(_ypos + pr.y())%2; d < pr.y()+pr.height(); d+=2 )
  {
    pp.drawPoint( dashX, d );
  }
}

void TextLineNrWidget::setScrollPosY( int ypos )
{
  ScrollPositionCalculator spc;
  int oy = _ypos;
  int ny = spc.calcPos( oy, ypos, height(), sizeHint().height() );

  if( oy == ny )
  {
    return;
  }

  _ypos = ny;
  super::scroll( 0, oy - _ypos );
}

QSize TextLineNrWidget::sizeHint() const
{
  QFontMetrics m(font());
  sc::Size width  = m.width('x') * _lnColumns + _lnLeftPad + _lnRightPad + dashLinePad;
  sc::Size height = m.height()   * _model->getLineCnt();
  return QSize( (int)width, (int)height );
}



syntax highlighted by Code2HTML, v. 0.9.1