/*------------------------------------------------------------*/
/* filename -       tlstview.cpp                              */
/*                                                            */
/* function(s)                                                */
/*                  TListViewer member functions              */
/*------------------------------------------------------------*/

/*------------------------------------------------------------*/
/*                                                            */
/*    Turbo Vision -  Version 1.0                             */
/*                                                            */
/*                                                            */
/*    Copyright (c) 1991 by Borland International             */
/*    All Rights Reserved.                                    */
/*                                                            */
/*------------------------------------------------------------*/

#define Uses_TKeys
#define Uses_TListViewer
#define Uses_TScrollBar
#define Uses_TDrawBuffer
#define Uses_TPoint
#define Uses_TEvent
#define Uses_TGroup
#define Uses_opstream
#define Uses_ipstream
#include "include\tv.h"

#include <string.h>

#define cpListViewer "\x1A\x1A\x1B\x1C\x1D"

TListViewer::TListViewer( const TRect& bounds,ushort aNumCols,
                          TScrollBar *aHScrollBar,TScrollBar *aVScrollBar) :
    TView( bounds ),
    range( 0 ),
    numCols( aNumCols ),
    focused( 0 ),
    topItem( 0 )
 {
  short arStep, pgStep;

  options |= ofFirstClick | ofSelectable;
  eventMask |= evBroadcast;
  if(aVScrollBar != 0)
   {
    if( numCols == 1 )
     {
      pgStep = size.y - 1;
      arStep = 1;
     }
    else
     {
      pgStep = size.y * numCols;
      arStep = size.y;
     }
    aVScrollBar->setStep( pgStep, arStep );
   }

  if(aHScrollBar != 0) aHScrollBar->setParams( 0,0,size.x-1,8,1); //ig 17.03.94

  hScrollBar = aHScrollBar;
  vScrollBar = aVScrollBar;
 }

void TListViewer::shutDown()
 {
  hScrollBar = 0;
  vScrollBar = 0;
  TView::shutDown();
 }

void TListViewer::changeBounds( const TRect& bounds )
 {
  TView::changeBounds( bounds );
  //if( hScrollBar != 0 )                             // ig 17.03.94
  //    hScrollBar->setStep( size.x / numCols, 1 );
 }

void TListViewer::getText( char *dest, short, short )
 {
  *dest = EOS;
 }

TPalette& TListViewer::getPalette() const
 {
  static TPalette palette( cpListViewer, sizeof( cpListViewer )-1 );
  return palette;
 }

void TListViewer::draw()
 {
  short i, j, item;
  ushort normalColor, selectedColor, focusedColor, color;
  short colWidth, curCol, indent;
  TDrawBuffer b;
  uchar scOff;

  if( (state&(sfSelected | sfActive)) == (sfSelected | sfActive))
   {
    normalColor = getColor(1);
    focusedColor = getColor(3);
    selectedColor = getColor(4);
   }
  else
   {
    normalColor = getColor(2);
    selectedColor = getColor(4);
   }

  if( hScrollBar != 0 ) indent = hScrollBar->value;
  else                  indent = 0;

  colWidth = size.x / numCols + 1;
  for( i = 0; i < size.y; i++ )
   {
    for( j = 0; j < numCols; j++ )
     {
      item =  j * size.y + i + topItem;
      curCol = j * colWidth;
      if( (state & (sfSelected | sfActive)) == (sfSelected | sfActive) &&
          focused == item && range > 0)
       {
        color = focusedColor;
        setCursor( curCol + 1, i );
        scOff = 0;
       }
      else
       if( item < range && isSelected(item) )
        {
         color = selectedColor;
         scOff = 2;
        }
       else
        {
         color = normalColor;
         scOff = 4;
        }

      b.moveChar( curCol, ' ', color, colWidth );
      if( item < range )
       {
        char text[256];
        getText( text, item, colWidth + indent );
        char buf[256];
        buf[0] = '\0';
        if ( strlen(text) > indent )
         {
          memmove( buf, text+indent, colWidth );
          buf[colWidth] = EOS;
         }
        b.moveStr( curCol+1, buf, color );
        if( showMarkers )
         {
          b.putChar( curCol, specialChars[scOff] );
          b.putChar( curCol+colWidth-2, specialChars[scOff+1] );
         }
       }
      else
       if( i == 0 && j == 0 )
          b.moveStr( curCol+1, "<empty>", getColor(1) );

      b.moveChar( curCol+colWidth-1, 179, getColor(5), 1 );
     }
    writeLine( 0, i, size.x, 1, b );
   }
 }

void TListViewer::focusItem( short item )
 {
  focused = item;
  if(vScrollBar != 0 )
      vScrollBar->setValue( item );
  else drawView();
  if(item < topItem )
   if( numCols == 1 )
          topItem = item;
   else
          topItem = item - item % size.y;
  else
   if( item >= topItem + size.y*numCols )
     if( numCols == 1 )
         topItem = item - size.y + 1;
     else
         topItem = item - item % size.y - (size.y * (numCols-1));
 }

void TListViewer::focusItemNum( short item )
 {
  if( item < 0 )
      item = 0;
  else
    if( item >= range && range > 0 )
        item = range - 1;

  if( range !=  0 )
      focusItem( item );
 }

Boolean TListViewer::isSelected( short item )
 {
  return Boolean( item == focused );
 }

void TListViewer::selectItem( short )
 {
  message(owner,evBroadcast,cmListItemSelected,this);
 }

void TListViewer::handleEvent( TEvent& event )
 {
  TPoint mouse;
  ushort colWidth;
  short  oldItem, newItem;
  ushort count;
  int mouseAutosToSkip = 4;

  TView::handleEvent(event);

  if( event.what == evMouseDown )
   {
    colWidth = size.x / numCols + 1;
    oldItem =  focused;
    mouse = makeLocal( event.mouse.where );
    newItem = mouse.y + (size.y * (mouse.x / colWidth)) + topItem;
    count = 0;
    do
     {
      if( newItem != oldItem )
          focusItemNum( newItem );
      oldItem = newItem;
      if( event.mouse.doubleClick && range > focused )
       {
        selectItem( focused );
        break;
       };
      mouse = makeLocal( event.mouse.where );
      if( mouseInView( event.mouse.where ) )
          newItem = mouse.y + (size.y * (mouse.x / colWidth)) + topItem;
      else
       {
        if( numCols == 1 )
         {
          if( event.what == evMouseAuto )
              count++;
          if( count == mouseAutosToSkip )
           {
            count = 0;
            if( mouse.y < 0 )
                newItem = focused - 1;
            else
                if( mouse.y >= size.y )
                    newItem = focused + 1;
           }
         }
        else
         {
          if( event.what == evMouseAuto )
              count++;
          if( count == mouseAutosToSkip )
           {
            count = 0;
            if( mouse.x < 0 )
                newItem = focused - size.y;
            else if( mouse.x >= size.x )
                newItem = focused + size.y;
            else if( mouse.y < 0 )
                newItem = focused - focused % size.y;
            else if( mouse.y > size.y )
                newItem = focused - focused % size.y + size.y - 1;
           }
         }
       }
     } while( mouseEvent( event, evMouseMove | evMouseAuto ) );
    focusItemNum( newItem );
    clearEvent( event );
   }
  else
   if( event.what == evKeyDown )
    {
     if (event.keyDown.charScan.charCode ==  ' ' && focused < range )
      {
       selectItem( focused );
       newItem = focused;
      }
     else
      {
       switch (ctrlToArrow(event.keyDown.keyCode))
        {
         case kbUp:
             newItem = focused - 1;
             break;
         case kbDown:
             newItem = focused + 1;
             break;
         case kbRight:
             if( numCols > 1 )
                 newItem = focused + size.y;
             else
                 return;
             break;
         case kbLeft:
             if( numCols > 1 )
                 newItem = focused - size.y;
             else
                 return;
             break;
         case kbPgDn:
             newItem = focused + size.y * numCols;
             break;
         case  kbPgUp:
             newItem = focused - size.y * numCols;
             break;
         case kbHome:
             newItem = topItem;
             break;
         case kbEnd:
             newItem = topItem + (size.y * numCols) - 1;
             break;
         case kbCtrlPgDn:
             newItem = range - 1;
             break;
         case kbCtrlPgUp:
             newItem = 0;
             break;
         default:
             return;
        }
      }
     focusItemNum(newItem);
     clearEvent(event);
    }
  else if( event.what == evBroadcast )
   {
    if( (options & ofSelectable) != 0 )
     {
      if( event.message.command == cmScrollBarClicked &&
            ( event.message.infoPtr == hScrollBar ||
              event.message.infoPtr == vScrollBar ) )
          select();
      else
       if( event.message.command == cmScrollBarChanged )
        {
         if( vScrollBar == event.message.infoPtr )
          {
           focusItemNum( vScrollBar->value );
           drawView();
          }
         else if( hScrollBar == event.message.infoPtr )
             drawView();
        }
     }
   }
 }

void TListViewer::setRange( short aRange )
 {
  range = aRange;
  if( focused > aRange ) focused = 0;         /* ig 16.03.94 */
  if( vScrollBar != 0 )
      vScrollBar->setParams( focused,
                             0,
                             aRange - 1,
                             vScrollBar->pgStep,vScrollBar->arStep);
  else drawView();
 }

void TListViewer::setState( ushort aState, Boolean enable )
 {
  TView::setState( aState, enable );
  if( (aState & (sfSelected | sfActive)) != 0 )
   {
    if( hScrollBar != 0 )
        if( getState(sfActive) )
            hScrollBar->show();
        else
            hScrollBar->hide();
    if( vScrollBar != 0 )
        if( getState(sfActive) )
            vScrollBar->show();
        else
            vScrollBar->hide();
    drawView();
   }
 }

#ifndef NO_TV_STREAMS
void TListViewer::write( opstream& os )
 {
    TView::write( os );
    os << hScrollBar << vScrollBar << numCols
       << topItem << focused << range;
 }

void *TListViewer::read( ipstream& is )
 {
    TView::read( is );
    is >> hScrollBar >> vScrollBar >> numCols
       >> topItem >> focused >> range;
    return this;
 }

TStreamable *TListViewer::build()
 {
    return new TListViewer( streamableInit );
 }

TListViewer::TListViewer( StreamableInit ) : TView( streamableInit )
 {
 }
#endif  // ifndef NO_TV_STREAMS


