/*
======================================================================
frame.c

Ernie Wright  17 Apr 05
MSVC 4.0

Functions that manage the storage of QV's images.  The images are
stored in an array of 10 pointers to Displayable.  Clients refer to
the images using an integer index into this array.
====================================================================== */

#include <windows.h>
#include "qv.h"


static Displayable *frame[ 10 ];
static ImageInfo iminfo;


/*
======================================================================
frameSyncInfo

Set ImageInfo fields from the specified frame.
====================================================================== */

void frameSyncInfo( int i )
{
   iminfo.disp    = frame[ i ];
   iminfo.width   = frame[ i ]->image->width;
   iminfo.height  = frame[ i ]->image->height;
   iminfo.caption = frame[ i ]->title;
}


/*
======================================================================
frameSyncUI

Update the user interface.  Set controls and redraw the display to
reflect current settings.
====================================================================== */

void frameSyncUI( HWND hwnd, int current, int redraw )
{
   int i;

   frameSyncInfo( current );

   radioSelect( hwnd, current );
   for ( i = 0; i < 10; i++ )
      radioEnable( hwnd, i, !frameIsEmpty( i ));

   toolbarSet( hwnd, iminfo.channel, iminfo.mask );

   statusCaption( iminfo.caption );
   statusZoom( iminfo.izoom );

   if ( redraw )
      imvUpdateImage( GetDlgItem( hwnd, IDW_DRAWWND ));
}


/*
======================================================================
frameInit()

Initialize the i-th image
====================================================================== */

int frameInit( Image *image, QVConfig *config, int i )
{
   frame[ i ] = createDisplayable( image );
   if ( !frame[ i ] ) return 0;

   image->black = config->black;
   image->white = config->white;
   frame[ i ]->hotInfo = config->hot;
   frame[ i ]->safeInfo = config->safe;
   realizeDisplayable( frame[ i ] );

   return 1;
}


/*
======================================================================
frameClear()

Free the i-th image.
====================================================================== */

void frameClear( int i )
{
   freeDisplayable( frame[ i ] );
   frame[ i ] = NULL;
   iminfo.disp = NULL;
}


/*
======================================================================
frameClearAll()

Free all of the images.
====================================================================== */

void frameClearAll( void )
{
   int i;

   for ( i = 0; i < 10; i++ ) {
      freeDisplayable( frame[ i ] );
      frame[ i ] = NULL;
   }
   iminfo.disp = NULL;
}


/*
======================================================================
frameIsEmpty()

Returns true if the frame is uninitialized.
====================================================================== */

int frameIsEmpty( int i )
{
   return frame[ i ] == NULL;
}


/*
======================================================================
frameOldest()

Returns the oldest image.  If all of the frames are currently empty
(which shouldn't happen), returns 0.
====================================================================== */

int frameOldest( void )
{
   int i, oldest = 0, t = 0x7FFFFFFF;

   for ( i = 0; i < 10; i++ ) {
      if ( !frameIsEmpty( i )) {
         if ( frame[ i ]->image->created < t ) {
            t = frame[ i ]->image->created;
            oldest = i;
         }
      }
   }
   return oldest;
}


/*
======================================================================
frameNewest()

Returns the most recently created image.  If all of the frames are
empty (which shouldn't happen), returns 0.
====================================================================== */

int frameNewest( void )
{
   int i, newest = 0, t = 0;

   for ( i = 0; i < 10; i++ ) {
      if ( !frameIsEmpty( i )) {
         if ( frame[ i ]->image->created > t ) {
            t = frame[ i ]->image->created;
            newest = i;
         }
      }
   }
   return newest;
}


/*
======================================================================
frameNextAvailable()

Returns the index of the next available frame slot.  If all 10 slots
are full, returns the index of the oldest image.
====================================================================== */

int frameNextAvailable( void )
{
   int i;

   for ( i = 0; i < 10; i++ )
      if ( frameIsEmpty( i ))
         return i;

   return frameOldest();
}


/*
======================================================================
frameGetInfo()

Return a pointer to the ImageInfo.
====================================================================== */

ImageInfo *frameGetInfo( void )
{
   return &iminfo;
}


/*
======================================================================
frameGetDisplayable()

Return a pointer to the i-th Displayable.
====================================================================== */

Displayable *frameGetDisplayable( int i )
{
   return frame[ i ];
}


/*
======================================================================
frameClone()

Copy the properties of a Displayable to all of the frames and realize
the altered frames.  If the Displayable is one of the frames, that
frame isn't altered or realized.  If the settings for a component of
the frame aren't different, that component also isn't realized.

The basic idea is to make all of the frames consistent with the
settings in 'disp'.  The easiest way to do this would be to simply
copy the 'disp' settings to every frame and realize all of the frames.
But this is very expensive in time, so we're careful to realize only
the DIBs for which the settings have actually changed.  An additional
constraint is that we will only copy settings and realize DIBs for
which the corresponding bit in 'parts' is set.  (The user may not want
to change all of the DIBs.)
====================================================================== */

void frameClone( Displayable *disp, int parts )
{
   int i, changed;

   for ( i = 0; i < 10; i++ ) {
      if ( !frameIsEmpty( i ) && frame[ i ] != disp ) {
         changed = 0;

         if ( parts & CHANGED_LEVELS ) {
            if ( floatChanged( frame[ i ]->image->black, disp->image->black, 10 ) ||
                 floatChanged( frame[ i ]->image->white, disp->image->white, 10 ))
            {
               frame[ i ]->image->black = disp->image->black;
               frame[ i ]->image->white = disp->image->white;
               changed |= CHANGED_LEVELS;
            }
         }

         if ( parts & CHANGED_HOT ) {
            if ( floatChanged( frame[ i ]->hotInfo.pedestal,
                    disp->hotInfo.pedestal, 10 ) ||
                 floatChanged( frame[ i ]->hotInfo.limComposite,
                    disp->hotInfo.limComposite, 10 ) ||
                 floatChanged( frame[ i ]->hotInfo.limChroma,
                    disp->hotInfo.limChroma, 10 ) ||
                 frame[ i ]->hotInfo.encoding != disp->hotInfo.encoding )
            {
               frame[ i ]->hotInfo = disp->hotInfo;
               changed |= CHANGED_HOT;
            }
         }

         if ( parts & CHANGED_SAFE ) {
            if ( floatChanged( frame[ i ]->safeInfo.aspect,
                    disp->safeInfo.aspect, 10 ) ||
                 floatChanged( frame[ i ]->safeInfo.margin,
                    disp->safeInfo.margin, 10 ) ||
                 frame[ i ]->safeInfo.types != disp->safeInfo.types ||
                 frame[ i ]->safeInfo.style != disp->safeInfo.style )
            {
               frame[ i ]->safeInfo = disp->safeInfo;
               changed |= CHANGED_SAFE;
            }
         }

         realizeDisplayableParts( frame[ i ], changed );
      }
   }
}