/* This file is part of the KDE project
   Copyright (C) 2001 Wilco Greven <greven@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

#include <kdebug.h>
#include <qimage.h>
#include <qpainter.h>
#include <qrect.h>

#include "centeringScrollview.h"

CenteringScrollview::CenteringScrollview( QWidget* parent, const char* name )
  : QScrollView( parent, name )
{
    _page = 0;
    centeringContents = false;    
    setFocusPolicy( QWidget::StrongFocus );
    viewport()->setFocusPolicy( QWidget::WheelFocus );
    URShadow.resize(4,4);
    BRShadow.resize(4,4);
    BLShadow.resize(4,4);
}

void CenteringScrollview::addChild( QWidget* page )
{
  if( page != 0 ) {
    QScrollView::addChild( page );
    centerContents();
    _page = page;
  }
}

bool CenteringScrollview::atTop() const
{
    return verticalScrollBar()->value() == verticalScrollBar()->minValue();
}

bool CenteringScrollview::atBottom() const 
{
    return verticalScrollBar()->value() == verticalScrollBar()->maxValue();
}

bool CenteringScrollview::readUp()
{
  if( atTop() )
    return false;
  else {
    int newValue = QMAX( verticalScrollBar()->value() - height() + 50,
			 verticalScrollBar()->minValue() );
    verticalScrollBar()->setValue( newValue );
    return true;
  }
}

bool CenteringScrollview::readDown()
{   
  if( atBottom() )
    return false;
  else {
    int newValue = QMIN( verticalScrollBar()->value() + height() - 50,
			 verticalScrollBar()->maxValue() );
    verticalScrollBar()->setValue( newValue );
    return true;
  }
}

void CenteringScrollview::scrollRight()
{
    horizontalScrollBar()->addLine();
}

void CenteringScrollview::scrollLeft()
{
    horizontalScrollBar()->subtractLine();
}

void CenteringScrollview::scrollDown()
{
    verticalScrollBar()->addLine();
}

void CenteringScrollview::scrollUp()
{
    verticalScrollBar()->subtractLine();
}

void CenteringScrollview::scrollBottom()
{
    verticalScrollBar()->setValue( verticalScrollBar()->maxValue() );
}

void CenteringScrollview::scrollTop()
{
    verticalScrollBar()->setValue( verticalScrollBar()->minValue() );
}

void CenteringScrollview::enableScrollBars( bool b )
{
    setHScrollBarMode( b ? Auto : AlwaysOff );
    setVScrollBarMode( b ? Auto : AlwaysOff );
}

void CenteringScrollview::keyPressEvent( QKeyEvent* e )
{   
    switch ( e->key() ) {
    case Key_Up:
	scrollUp();
	break;
    case Key_Down:
	scrollDown();
	break;
    case Key_Left:
	scrollLeft();
	break;
    case Key_Right:
	scrollRight();
	break;
    default:
	e->ignore();
	return;
    }
    e->accept();
}

void CenteringScrollview::viewportResizeEvent( QResizeEvent* e )
{
  QScrollView::viewportResizeEvent( e );
  emit viewSizeChanged( viewport()->size() );
  centerContents();
}

void CenteringScrollview::centerContents()
{
  if( !_page ) 
    return;
  
  int newX = 0;
  int newY = 0;

  QSize newViewportSize = viewportSize( _page->width(), _page->height() );
    
  if( newViewportSize.width() > _page->width() )
    newX = ( newViewportSize.width() - _page->width() )/2;
  if( newViewportSize.height() > _page->height() )
    newY = ( newViewportSize.height() - _page->height() )/2;

  // Note: setting the centeringContents flag here is absolutely
  // necessary to prevent infinite recursion (with stack overflow and
  // crash) when the overloaded version of resizeContents() is called.
  centeringContents = true;
  moveChild( _page, newX, newY );
  centeringContents = false;

  // Re-draw the viewport background so that old shadows are removed
  viewport()->update();
}

void CenteringScrollview::resizeContents(int w, int h)
{
  QScrollView::resizeContents(w,h);
  if (!centeringContents)
    centerContents();
}

void CenteringScrollview::contentsWheelEvent ( QWheelEvent * e )
{
  emit(wheelEventReceived(e));
}




// The following tables store grey values for roundish shadow
// corners. The were shamelessly stolen from kdelibs/kdefx/kstyle.cpp

const int bottom_right_corner[16] =
  { 61, 71, 85, 95,
    71, 78, 89, 96,
    85, 89, 95, 98,
    95, 97, 98, 99 };
const int bottom_left_corner[16] =
  { 95, 85, 71, 61,
    97, 89, 78, 71,
    98, 95, 89, 85,
    99, 98, 96, 95 };
const int shadow_strip[4] =
  { 56, 67, 83, 94 };


void CenteringScrollview::drawContents( QPainter *p, int, int, int, int )
{
  // Shadows are only drawn if a child widget exists, is shown and not
  // 0x0 size, and if the background is not black
  if ( (_page != 0) && _page->isShown() && (_page->height() > 8) &&
       (viewport()->paletteBackgroundColor() != Qt::black) ) {
    
    QColor backgroundColor = viewport()->paletteBackgroundColor();

    // (Re-)generate the Pixmaps for the shadow corners, if necessary
    if (backgroundColor != viewportBackgroundColorForCorners) {
      viewportBackgroundColorForCorners = backgroundColor;
      QImage tmp(4, 4, 32);

      for(int x=0; x<4; x++)
	for(int y=0; y<4; y++)
	  tmp.setPixel(x, y, backgroundColor.light(bottom_right_corner[x+4*y]).rgb() );
      BRShadow.convertFromImage(tmp);

      for(int x=0; x<4; x++)
	for(int y=0; y<4; y++)
	  tmp.setPixel(x, y, backgroundColor.light(bottom_left_corner[x+4*y]).rgb() );
      BLShadow.convertFromImage(tmp);

      URShadow.convertFromImage(tmp.mirror(true, true));
    }

    // Draw right and bottom shadows
    for(int i=0; i<4; i++) {
      p->setPen(backgroundColor.light(shadow_strip[i]));
      // Right shadow
      p->drawLine(childX(_page) + _page->width() + i, childY(_page) + 8,
		  childX(_page) + _page->width() + i, childY(_page) + _page->height());
      // Bottom shadow
      p->drawLine(childX(_page) + 8, childY(_page) + _page->height() + i,
		  childX(_page) + _page->width(), childY(_page) + _page->height() + i );
    }
    // Draw shadow corners
    p->drawPixmap(childX(_page) + _page->width(), childY(_page) + _page->height(), BRShadow);
    p->drawPixmap(childX(_page)+4, childY(_page) + _page->height(), BLShadow);
    p->drawPixmap(childX(_page) + _page->width(), childY(_page)+4, URShadow);
  }
}

#include "centeringScrollview.moc"
