/*
 * stddlg.cc
 *
 * Turbo Vision - Version 2.0
 *
 * Copyright (c) 1994 by Borland International
 * All Rights Reserved.
 *
 * Modified by Sergio Sigala <sergio@sigala.it>
 */

#define Uses_MsgBox
#define Uses_TKeys
#define Uses_TFileInputLine
#define Uses_TEvent
#define Uses_TSortedListBox
#define Uses_TSearchRec
#define Uses_TFileInfoPane
#define Uses_TDrawBuffer
#define Uses_TFileDialog
#define Uses_TSortedCollection
#include <tvision/tv.h>

#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void fexpand( char * );

#define cpInfoPane "\x1E"

TFileInputLine::TFileInputLine( const TRect& bounds, short aMaxLen ) :
    TInputLine( bounds, aMaxLen )
{
    eventMask |= evBroadcast;
}

void TFileInputLine::handleEvent( TEvent& event )
{
    TInputLine::handleEvent(event);
    if( event.what == evBroadcast &&
        event.message.command == cmFileFocused &&
        !(state & sfSelected)
      )
        {
#ifndef __UNPATCHED
    // Prevents incorrect display in the input line if wildCard has
    // already been expanded.
    if( (((TSearchRec *)event.message.infoPtr)->attr & FA_DIREC) != 0 )
    {
        strcpy( data, ((TFileDialog *)owner)->wildCard );
        if(!strchr(data, ':') && !strchr(data, '/'))
        {
            strcpy( data, ((TSearchRec *)event.message.infoPtr)->name );
            strcat( data, "/" );
            strcat( data, ((TFileDialog *)owner)->wildCard );
        }
        else
        {
            // Insert "<name>\\" between last name or wildcard and last '/'
            fexpand(data);    // Insure complete expansion to begin with
            char *tmp = strrchr(data, '/') + 1;
            char *nm = ((TSearchRec *)event.message.infoPtr)->name;
            memmove(tmp + strlen(nm) + 1, tmp, strlen(tmp) + 1);
            memcpy(tmp, nm, strlen(nm));
            *(tmp + strlen(nm)) = '/';
            fexpand(data);    // Expand again incase it was '..'.
        }
    }
#else
        if( (((TSearchRec *)event.message.infoPtr)->attr & FA_DIREC) != 0 )
            {
            strcpy( data, ((TSearchRec *)event.message.infoPtr)->name );
            strcat( data, "/" );
            strcat( data, ((TFileDialog *)owner)->wildCard );
            }
#endif
        else
            strcpy( data, ((TSearchRec *)event.message.infoPtr)->name );
        drawView();
        }
}

TSortedListBox::TSortedListBox( const TRect& bounds,
                                ushort aNumCols,
                                TScrollBar *aScrollBar) :
    TListBox(bounds, aNumCols, aScrollBar),
    shiftState( 0 ),
    searchPos( -1 )
{
    showCursor();
    setCursor(1, 0);
}

static Boolean equal( const char *s1, const char *s2, ushort count)
{
	/* SS: use a standard function */

	return Boolean( strncasecmp( s1, s2, count ) == 0 );
}

void TSortedListBox::handleEvent(TEvent& event)
{
    char curString[256], newString[256];
    void* k;
    int value;
    short oldPos, oldValue;

    oldValue = focused;
    TListBox::handleEvent( event );
    if( oldValue != focused ||
        ( event.what == evBroadcast &&
          event.message.command == cmReleasedFocus )
      )
        searchPos = -1;
    if( event.what == evKeyDown )
        {
        if( event.keyDown.charScan.charCode != 0 )
            {
            value = focused;
            if( value < range )
                getText( curString, (short) value, 255 );
            else
                *curString = EOS;
            oldPos = searchPos;
            if( event.keyDown.keyCode == kbBack )
                {
                if( searchPos == -1 )
                    return;
                searchPos--;
                if( searchPos == -1 )
                    shiftState = (ushort) event.keyDown.controlKeyState;
                curString[searchPos+1] = EOS;
                }
            else if( (event.keyDown.charScan.charCode == '.') )
                {
                char *loc = strchr( curString, '.' );
                if( loc == 0 )
                    searchPos = -1;
                else
                    searchPos = short(loc - curString);
                }
            else
                {
                searchPos++;
                if( searchPos == 0 )
                    shiftState = (ushort) event.keyDown.controlKeyState;
                curString[searchPos] = event.keyDown.charScan.charCode;
                curString[searchPos+1] = EOS;
                }
            k = getKey(curString);

	    /* SS: this makes g++ happy */

	    ccIndex c = (ccIndex) value;
            list()->search( k, c );
		value = (int) c;

            if( value < range )
                {
                getText( newString, (short) value, 255 );
                if( equal( curString, newString, (ushort) (searchPos+1) ) )
                    {
                    if( value != oldValue )
                        {
                        focusItem( (short) value );
                        setCursor( cursor.x+searchPos+1, cursor.y );
                        }
                    else
                        setCursor(cursor.x+(searchPos-oldPos), cursor.y );
                    }
                else
                    searchPos = oldPos;
                }
            else
                searchPos = oldPos;
            if( searchPos != oldPos ||
                isalpha( event.keyDown.charScan.charCode )
              )
                clearEvent(event);
            }
        }
}

void* TSortedListBox::getKey( const char *s )
{
    return (void *)s;
}

void TSortedListBox::newList( TSortedCollection *aList )
{
    TListBox::newList( aList );
    searchPos = -1;
}

TFileInfoPane::TFileInfoPane( const TRect& bounds ) :
    TView(bounds)
{
    eventMask |= evBroadcast;
}

void TFileInfoPane::draw()
{
    Boolean PM;
    TDrawBuffer b;
    ushort  color;
    ftime *time;
    char path[PATH_MAX];

#ifndef __UNPATCHED
    // Prevents incorrect directory name display in info pane if wildCard
    // has already been expanded.
    strcpy(path, ((TFileDialog *)owner)->wildCard );
    if(!strchr(path, ':') && !strchr(path, '/'))
    {
        strcpy( path, ((TFileDialog *)owner)->directory );
        strcat( path, ((TFileDialog *)owner)->wildCard );
        fexpand( path );
    }
#else
    strcpy( path, ((TFileDialog *)owner)->directory );
    strcat( path, ((TFileDialog *)owner)->wildCard );
    fexpand( path );
#endif

    color = getColor(0x01);
    b.moveChar( 0, ' ', color, (ushort) size.x );
    b.moveStr( 1, path, color );
    writeLine( 0, 0, (ushort) size.x, 1, b );

    b.moveChar( 0, ' ', color, (ushort) size.x );
    b.moveStr( 1, file_block.name, color );

    if( *(file_block.name) != EOS )
        {

        char buf[10];

	/* SS: little fix */

	sprintf(buf, "%ld", file_block.size);
        b.moveStr( 14, buf, color );

        time = (ftime *) &file_block.time;
        b.moveStr( 25, months[time->ft_month], color );

	sprintf(buf, "%02d", time->ft_day);
        b.moveStr( 29, buf, color );

        b.putChar( 31, ',' );

	sprintf(buf, "%d", time->ft_year+1980);
        b.moveStr( 32, buf, color );

        PM = Boolean(time->ft_hour >= 12 );
        time->ft_hour %= 12;

        if( time->ft_hour == 0 )
            time->ft_hour = 12;

	sprintf(buf, "%02d", time->ft_hour);
        b.moveStr( 38, buf, color );
        b.putChar( 40, ':' );

	sprintf(buf, "%02d", time->ft_min);
        b.moveStr( 41, buf, color );

        if( PM )
            b.moveStr( 43, pmText, color );
        else
            b.moveStr( 43, amText, color );
        }

    writeLine(0, 1, (ushort) size.x, 1, b );
    b.moveChar( 0, ' ', color, (ushort) size.x );
    writeLine( 0, 2, (ushort) size.x, (ushort) (size.y-2), b);
}

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

void TFileInfoPane::handleEvent( TEvent& event )
{
    TView::handleEvent(event);
    if( event.what == evBroadcast && event.message.command == cmFileFocused )
        {
        file_block = *((TSearchRec *)(event.message.infoPtr));
        drawView();
        }
}

#if !defined(NO_STREAMABLE)

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

#ifndef __UNPATCHED
TStreamable *TSortedListBox::build()
{
    return new TSortedListBox( streamableInit );
}

void *TSortedListBox::read( ipstream& is )
{
    TListBox::read(is);

    // Must initialize these or serious memory overwrite
    // problems can occur!
    searchPos = -1;
    shiftState = 0;

    return this;
}
#endif

#endif


syntax highlighted by Code2HTML, v. 0.9.1