619 lines
16 KiB
C++
619 lines
16 KiB
C++
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT MICROSOFT CORPORATION, 1998
|
|
*
|
|
* TITLE: VWIASET.H
|
|
*
|
|
* VERSION: 1.0
|
|
*
|
|
* AUTHOR: ShaunIv
|
|
*
|
|
* DATE: 1/10/2000
|
|
*
|
|
* DESCRIPTION: Encapsulate the differences between LIST and RANGE properties
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#ifndef __VWIASET_H_INCLUDED
|
|
#define __VWIASET_H_INCLUDED
|
|
|
|
#include <windows.h>
|
|
#include "pshelper.h"
|
|
|
|
class CValidWiaSettings
|
|
{
|
|
private:
|
|
//
|
|
// Indices into array for range values
|
|
//
|
|
enum
|
|
{
|
|
MinValue = 0,
|
|
MaxValue = 1,
|
|
StepValue = 2
|
|
};
|
|
|
|
private:
|
|
CSimpleDynamicArray<LONG> m_ValueList;
|
|
LONG m_nInitialValue;
|
|
LONG m_nType;
|
|
|
|
public:
|
|
CValidWiaSettings(void)
|
|
: m_nType(0),
|
|
m_nInitialValue(0)
|
|
{
|
|
}
|
|
CValidWiaSettings( IUnknown *pUnknown, const PropStorageHelpers::CPropertyId &propertyName )
|
|
: m_nType(0),
|
|
m_nInitialValue(0)
|
|
{
|
|
Read( pUnknown, propertyName );
|
|
}
|
|
CValidWiaSettings( const CValidWiaSettings &other )
|
|
: m_nType(0),
|
|
m_nInitialValue(0)
|
|
{
|
|
Assign(other);
|
|
}
|
|
CValidWiaSettings &operator=( const CValidWiaSettings &other )
|
|
{
|
|
if (&other != this)
|
|
{
|
|
Assign(other);
|
|
}
|
|
return *this;
|
|
}
|
|
CValidWiaSettings &Assign( const CValidWiaSettings &other )
|
|
{
|
|
Destroy();
|
|
m_nType = other.Type();
|
|
m_ValueList = other.ValueList();
|
|
m_nInitialValue = other.InitialValue();
|
|
if (!IsValid())
|
|
{
|
|
Destroy();
|
|
}
|
|
return *this;
|
|
}
|
|
LONG Type(void) const
|
|
{
|
|
return m_nType;
|
|
}
|
|
LONG InitialValue(void) const
|
|
{
|
|
return m_nInitialValue;
|
|
}
|
|
const CSimpleDynamicArray<LONG> &ValueList(void) const
|
|
{
|
|
return m_ValueList;
|
|
}
|
|
CSimpleDynamicArray<LONG> &ValueList(void)
|
|
{
|
|
return m_ValueList;
|
|
}
|
|
void Destroy(void)
|
|
{
|
|
m_nType = 0;
|
|
m_nInitialValue = 0;
|
|
m_ValueList.Destroy();
|
|
}
|
|
bool IsValid(void) const
|
|
{
|
|
if (IsList())
|
|
{
|
|
return (m_ValueList.Size() != 0);
|
|
}
|
|
else if (IsRange())
|
|
{
|
|
return (m_ValueList.Size() == 3);
|
|
}
|
|
else return false;
|
|
}
|
|
bool Read( IUnknown *pUnknown, const PropStorageHelpers::CPropertyId &propertyName )
|
|
{
|
|
bool bSuccess = false;
|
|
Destroy();
|
|
m_nType = 0;
|
|
|
|
//
|
|
// If we can't read this value, we're done
|
|
//
|
|
if (!PropStorageHelpers::GetProperty( pUnknown, propertyName, m_nInitialValue ))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ULONG nAccessFlags;
|
|
if (PropStorageHelpers::GetPropertyAccessFlags( pUnknown, propertyName, nAccessFlags ))
|
|
{
|
|
if (nAccessFlags & WIA_PROP_LIST)
|
|
{
|
|
if (PropStorageHelpers::GetPropertyList( pUnknown, propertyName, m_ValueList ))
|
|
{
|
|
m_nType = WIA_PROP_LIST;
|
|
bSuccess = (m_ValueList.Size() != 0);
|
|
}
|
|
}
|
|
else if (nAccessFlags & WIA_PROP_RANGE)
|
|
{
|
|
PropStorageHelpers::CPropertyRange PropertyRange;
|
|
if (PropStorageHelpers::GetPropertyRange( pUnknown, propertyName, PropertyRange ))
|
|
{
|
|
m_nType = WIA_PROP_RANGE;
|
|
m_ValueList.Append( PropertyRange.nMin );
|
|
m_ValueList.Append( PropertyRange.nMax );
|
|
m_ValueList.Append( PropertyRange.nStep );
|
|
bSuccess = (m_ValueList.Size() == 3);
|
|
}
|
|
}
|
|
}
|
|
if (!bSuccess)
|
|
{
|
|
Destroy();
|
|
}
|
|
return bSuccess;
|
|
}
|
|
bool FindClosestValueByRoundingDown( LONG &nValue ) const
|
|
{
|
|
//
|
|
// Make sure we have a valid item
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (IsRange())
|
|
{
|
|
//
|
|
// Make sure we are in the legal range
|
|
//
|
|
nValue = WiaUiUtil::Min( WiaUiUtil::Max( m_ValueList[MinValue], nValue ), m_ValueList[MaxValue] );
|
|
|
|
//
|
|
// Divide the difference between nValue and min by nStep, then multiply by nStep to
|
|
// get rid of the remainder to round down to the nearest value
|
|
//
|
|
nValue = m_ValueList[MinValue] + (((nValue - m_ValueList[MinValue]) / m_ValueList[StepValue]) * m_ValueList[StepValue]);
|
|
return true;
|
|
}
|
|
else if (IsList() && m_ValueList.Size())
|
|
{
|
|
//
|
|
// Assume the list is sorted, so we can take the first item and assume it is the minimum value
|
|
//
|
|
LONG nResult = m_ValueList[0];
|
|
for (int i=0;i<m_ValueList.Size();i++)
|
|
{
|
|
if (m_ValueList[i] > nValue)
|
|
{
|
|
break;
|
|
}
|
|
nResult = m_ValueList[i];
|
|
}
|
|
nValue = nResult;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
bool FindClosestValue( LONG &nValue ) const
|
|
{
|
|
LONG nFloor=nValue;
|
|
if (FindClosestValueByRoundingDown(nFloor))
|
|
{
|
|
LONG nCeiling=nFloor;
|
|
if (Increment(nCeiling))
|
|
{
|
|
if (nValue - nFloor < nCeiling - nValue)
|
|
{
|
|
nValue = nFloor;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
nValue = nCeiling;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
bool IsLegalValue( LONG nValue ) const
|
|
{
|
|
LONG nTestValue = nValue;
|
|
if (FindClosestValueByRoundingDown(nTestValue))
|
|
{
|
|
return (nTestValue == nValue);
|
|
}
|
|
return false;
|
|
}
|
|
int FindIndexOfItem( LONG nCurrentValue ) const
|
|
{
|
|
if (IsRange())
|
|
{
|
|
//
|
|
// Make sure we are in the legal range
|
|
//
|
|
nCurrentValue = WiaUiUtil::Min( WiaUiUtil::Max( m_ValueList[MinValue], nCurrentValue ), m_ValueList[MaxValue] );
|
|
|
|
return (nCurrentValue - m_ValueList[MinValue]) / m_ValueList[StepValue];
|
|
}
|
|
else if (IsList() && m_ValueList.Size())
|
|
{
|
|
//
|
|
// Assume the list is sorted, so we can take the first item and assume it is the minimum value
|
|
//
|
|
for (int i=0;i<m_ValueList.Size();i++)
|
|
{
|
|
if (m_ValueList[i] == nCurrentValue)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// returns -1 to indicate failure
|
|
//
|
|
return -1;
|
|
}
|
|
bool Increment( LONG &nCurrentValue ) const
|
|
{
|
|
//
|
|
// Round us off. This will also take care of validation.
|
|
//
|
|
if (!FindClosestValueByRoundingDown( nCurrentValue ))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (IsRange())
|
|
{
|
|
//
|
|
// Let FindClosestValueByRoundingDown take care of making sure that we don't exceed the maximum
|
|
//
|
|
nCurrentValue += m_ValueList[StepValue];
|
|
return FindClosestValueByRoundingDown( nCurrentValue );
|
|
}
|
|
else if (IsList() && m_ValueList.Size())
|
|
{
|
|
int nIndex = FindIndexOfItem( nCurrentValue );
|
|
|
|
//
|
|
// Make sure we are in the list
|
|
//
|
|
if (nIndex < 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Get the next value
|
|
//
|
|
nIndex++;
|
|
|
|
//
|
|
// Make sure we aren't off the end of the list
|
|
//
|
|
if (nIndex >= m_ValueList.Size())
|
|
{
|
|
nIndex = m_ValueList.Size() - 1;
|
|
}
|
|
|
|
//
|
|
// Return it
|
|
//
|
|
nCurrentValue = m_ValueList[nIndex];
|
|
|
|
//
|
|
// Everything is OK
|
|
//
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
bool Decrement( LONG &nCurrentValue ) const
|
|
{
|
|
//
|
|
// Round us off. This will also take care of validation.
|
|
//
|
|
if (!FindClosestValueByRoundingDown( nCurrentValue ))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (IsRange())
|
|
{
|
|
//
|
|
// Let FindClosestValueByRoundingDown take care of making sure that we don't go under the minimum
|
|
//
|
|
nCurrentValue -= m_ValueList[StepValue];
|
|
return FindClosestValueByRoundingDown( nCurrentValue );
|
|
}
|
|
else if (IsList() && m_ValueList.Size())
|
|
{
|
|
int nIndex = FindIndexOfItem( nCurrentValue );
|
|
|
|
//
|
|
// Make sure we are in the list
|
|
//
|
|
if (nIndex < 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Get the previous value
|
|
//
|
|
nIndex--;
|
|
|
|
//
|
|
// Make sure we aren't before the beginning of the list
|
|
//
|
|
if (nIndex < 0)
|
|
{
|
|
nIndex = 0;
|
|
}
|
|
|
|
//
|
|
// Return it
|
|
//
|
|
nCurrentValue = m_ValueList[nIndex];
|
|
|
|
//
|
|
// Everything is OK
|
|
//
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
LONG GetItemCount(void) const
|
|
{
|
|
if (IsList())
|
|
{
|
|
return m_ValueList.Size();
|
|
}
|
|
else if (IsRange())
|
|
{
|
|
//
|
|
// Calculate the number of steps between the minimum and maximum
|
|
//
|
|
return ((m_ValueList[MaxValue] - m_ValueList[MinValue]) / m_ValueList[StepValue]) + 1;
|
|
}
|
|
return 0;
|
|
}
|
|
bool GetItemAtIndex( int nIndex, LONG &nItem ) const
|
|
{
|
|
if (!IsValid())
|
|
{
|
|
return false;
|
|
}
|
|
if (IsList() && nIndex >= 0 && nIndex < m_ValueList.Size())
|
|
{
|
|
nItem = m_ValueList[nIndex];
|
|
return true;
|
|
}
|
|
else if (IsRange() && nIndex < GetItemCount())
|
|
{
|
|
//
|
|
// Return the minimum + nIndex * stepvalue
|
|
//
|
|
nItem = m_ValueList[MinValue] + (m_ValueList[StepValue] * nIndex);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
bool FindIntersection( const CValidWiaSettings &Set1, const CValidWiaSettings &Set2 )
|
|
{
|
|
//
|
|
// We are modifying ourselves, so clear all of our data
|
|
//
|
|
Destroy();
|
|
|
|
//
|
|
// If either set is invalid, no intersection
|
|
//
|
|
if (!Set1.IsValid() || !Set2.IsValid())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// If either a or b is a set (or both), just add all of the items
|
|
// that are legal in both to ourself and set the type to a LIST
|
|
//
|
|
if (Set1.IsList())
|
|
{
|
|
m_nType = WIA_PROP_LIST;
|
|
for (int i=0;i<Set1.GetItemCount();i++)
|
|
{
|
|
LONG nItem;
|
|
if (Set1.GetItemAtIndex(i,nItem))
|
|
{
|
|
if (Set2.IsLegalValue(nItem))
|
|
{
|
|
m_ValueList.Append(nItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Figure out where to get the initial value from
|
|
//
|
|
if (IsLegalValue(Set1.InitialValue()))
|
|
{
|
|
m_nInitialValue = Set1.InitialValue();
|
|
}
|
|
else if (IsLegalValue(Set2.InitialValue()))
|
|
{
|
|
m_nInitialValue = Set2.InitialValue();
|
|
}
|
|
else
|
|
{
|
|
if (!FindClosestValueByRoundingDown( m_nInitialValue ))
|
|
{
|
|
//
|
|
// As a last resort, use the first value
|
|
//
|
|
GetItemAtIndex(0,m_nInitialValue);
|
|
}
|
|
}
|
|
|
|
return (m_ValueList.Size() != 0);
|
|
}
|
|
else if (Set2.IsList())
|
|
{
|
|
m_nType = WIA_PROP_LIST;
|
|
for (int i=0;i<Set2.GetItemCount();i++)
|
|
{
|
|
LONG nItem;
|
|
if (Set2.GetItemAtIndex(i,nItem))
|
|
{
|
|
if (Set1.IsLegalValue(nItem))
|
|
{
|
|
m_ValueList.Append(nItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Figure out where to get the initial value from
|
|
//
|
|
if (IsLegalValue(Set2.InitialValue()))
|
|
{
|
|
m_nInitialValue = Set2.InitialValue();
|
|
}
|
|
else if (IsLegalValue(Set1.InitialValue()))
|
|
{
|
|
m_nInitialValue = Set1.InitialValue();
|
|
}
|
|
else
|
|
{
|
|
if (!FindClosestValueByRoundingDown( m_nInitialValue ))
|
|
{
|
|
//
|
|
// As a last resort, use the first value
|
|
//
|
|
GetItemAtIndex(0,m_nInitialValue);
|
|
}
|
|
}
|
|
|
|
return (m_ValueList.Size() != 0);
|
|
}
|
|
//
|
|
// Both are ranges.
|
|
// BUGBUG: I may have to actually figure out how to do this in a more sophisticated
|
|
// way. Basically, I am taking the minimum of the two maximums and the maximum of the
|
|
// two minimums if and only if the at least one of the minimums is in the set of the
|
|
// other items and they have the same step value
|
|
//
|
|
else if (Set1.IsLegalValue(Set2.Min()) || Set2.IsLegalValue(Set1.Min()) && Set1.Step() == Set2.Step())
|
|
{
|
|
m_nType = WIA_PROP_RANGE;
|
|
|
|
//
|
|
// Minimum, Maximum, Step
|
|
//
|
|
m_ValueList.Append(WiaUiUtil::Max(Set1.Min(),Set2.Min()));
|
|
m_ValueList.Append(WiaUiUtil::Min(Set1.Max(),Set2.Max()));
|
|
m_ValueList.Append(Set1.Step());
|
|
|
|
//
|
|
// Figure out where to get the initial value from
|
|
//
|
|
if (IsLegalValue(Set2.InitialValue()))
|
|
{
|
|
m_nInitialValue = Set2.InitialValue();
|
|
}
|
|
else if (IsLegalValue(Set1.InitialValue()))
|
|
{
|
|
m_nInitialValue = Set1.InitialValue();
|
|
}
|
|
else
|
|
{
|
|
if (!FindClosestValueByRoundingDown( m_nInitialValue ))
|
|
{
|
|
//
|
|
// As a last resort, use the first value
|
|
//
|
|
GetItemAtIndex(0,m_nInitialValue);
|
|
}
|
|
}
|
|
|
|
return (m_ValueList.Size() == 3);
|
|
}
|
|
return true;
|
|
}
|
|
LONG Min(void) const
|
|
{
|
|
if (!IsValid())
|
|
{
|
|
return 0;
|
|
}
|
|
if (IsList())
|
|
{
|
|
return (m_ValueList[0]);
|
|
}
|
|
else if (IsRange())
|
|
{
|
|
return (m_ValueList[MinValue]);
|
|
}
|
|
return 0;
|
|
}
|
|
LONG Max(void) const
|
|
{
|
|
if (!IsValid())
|
|
{
|
|
return 0;
|
|
}
|
|
if (IsList())
|
|
{
|
|
return (m_ValueList[m_ValueList.Size()-1]);
|
|
}
|
|
else if (IsRange())
|
|
{
|
|
return (m_ValueList[MaxValue]);
|
|
}
|
|
return 0;
|
|
}
|
|
LONG Step(void) const
|
|
{
|
|
if (IsRange())
|
|
{
|
|
return (m_ValueList[StepValue]);
|
|
}
|
|
return 0;
|
|
}
|
|
bool IsRange(void) const
|
|
{
|
|
return (m_nType == WIA_PROP_RANGE);
|
|
}
|
|
bool IsList(void) const
|
|
{
|
|
return (m_nType == WIA_PROP_LIST);
|
|
}
|
|
|
|
static bool SetNumericPropertyOnBoundary( IUnknown *pUnknown, const PropStorageHelpers::CPropertyId &propertyName, LONG nValue )
|
|
{
|
|
CValidWiaSettings ValidWiaSettings;
|
|
if (!ValidWiaSettings.Read( pUnknown, propertyName ))
|
|
{
|
|
return false;
|
|
}
|
|
if (!ValidWiaSettings.FindClosestValueByRoundingDown(nValue))
|
|
{
|
|
return false;
|
|
}
|
|
if (!PropStorageHelpers::SetProperty( pUnknown, propertyName, nValue ))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
};
|
|
|
|
#endif //__VWIASET_H_INCLUDED
|
|
|