Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

618 lines
16 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 1998
  4. *
  5. * TITLE: VWIASET.H
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: ShaunIv
  10. *
  11. * DATE: 1/10/2000
  12. *
  13. * DESCRIPTION: Encapsulate the differences between LIST and RANGE properties
  14. *
  15. *******************************************************************************/
  16. #ifndef __VWIASET_H_INCLUDED
  17. #define __VWIASET_H_INCLUDED
  18. #include <windows.h>
  19. #include "pshelper.h"
  20. class CValidWiaSettings
  21. {
  22. private:
  23. //
  24. // Indices into array for range values
  25. //
  26. enum
  27. {
  28. MinValue = 0,
  29. MaxValue = 1,
  30. StepValue = 2
  31. };
  32. private:
  33. CSimpleDynamicArray<LONG> m_ValueList;
  34. LONG m_nInitialValue;
  35. LONG m_nType;
  36. public:
  37. CValidWiaSettings(void)
  38. : m_nType(0),
  39. m_nInitialValue(0)
  40. {
  41. }
  42. CValidWiaSettings( IUnknown *pUnknown, const PropStorageHelpers::CPropertyId &propertyName )
  43. : m_nType(0),
  44. m_nInitialValue(0)
  45. {
  46. Read( pUnknown, propertyName );
  47. }
  48. CValidWiaSettings( const CValidWiaSettings &other )
  49. : m_nType(0),
  50. m_nInitialValue(0)
  51. {
  52. Assign(other);
  53. }
  54. CValidWiaSettings &operator=( const CValidWiaSettings &other )
  55. {
  56. if (&other != this)
  57. {
  58. Assign(other);
  59. }
  60. return *this;
  61. }
  62. CValidWiaSettings &Assign( const CValidWiaSettings &other )
  63. {
  64. Destroy();
  65. m_nType = other.Type();
  66. m_ValueList = other.ValueList();
  67. m_nInitialValue = other.InitialValue();
  68. if (!IsValid())
  69. {
  70. Destroy();
  71. }
  72. return *this;
  73. }
  74. LONG Type(void) const
  75. {
  76. return m_nType;
  77. }
  78. LONG InitialValue(void) const
  79. {
  80. return m_nInitialValue;
  81. }
  82. const CSimpleDynamicArray<LONG> &ValueList(void) const
  83. {
  84. return m_ValueList;
  85. }
  86. CSimpleDynamicArray<LONG> &ValueList(void)
  87. {
  88. return m_ValueList;
  89. }
  90. void Destroy(void)
  91. {
  92. m_nType = 0;
  93. m_nInitialValue = 0;
  94. m_ValueList.Destroy();
  95. }
  96. bool IsValid(void) const
  97. {
  98. if (IsList())
  99. {
  100. return (m_ValueList.Size() != 0);
  101. }
  102. else if (IsRange())
  103. {
  104. return (m_ValueList.Size() == 3);
  105. }
  106. else return false;
  107. }
  108. bool Read( IUnknown *pUnknown, const PropStorageHelpers::CPropertyId &propertyName )
  109. {
  110. bool bSuccess = false;
  111. Destroy();
  112. m_nType = 0;
  113. //
  114. // If we can't read this value, we're done
  115. //
  116. if (!PropStorageHelpers::GetProperty( pUnknown, propertyName, m_nInitialValue ))
  117. {
  118. return false;
  119. }
  120. ULONG nAccessFlags;
  121. if (PropStorageHelpers::GetPropertyAccessFlags( pUnknown, propertyName, nAccessFlags ))
  122. {
  123. if (nAccessFlags & WIA_PROP_LIST)
  124. {
  125. if (PropStorageHelpers::GetPropertyList( pUnknown, propertyName, m_ValueList ))
  126. {
  127. m_nType = WIA_PROP_LIST;
  128. bSuccess = (m_ValueList.Size() != 0);
  129. }
  130. }
  131. else if (nAccessFlags & WIA_PROP_RANGE)
  132. {
  133. PropStorageHelpers::CPropertyRange PropertyRange;
  134. if (PropStorageHelpers::GetPropertyRange( pUnknown, propertyName, PropertyRange ))
  135. {
  136. m_nType = WIA_PROP_RANGE;
  137. m_ValueList.Append( PropertyRange.nMin );
  138. m_ValueList.Append( PropertyRange.nMax );
  139. m_ValueList.Append( PropertyRange.nStep );
  140. bSuccess = (m_ValueList.Size() == 3);
  141. }
  142. }
  143. }
  144. if (!bSuccess)
  145. {
  146. Destroy();
  147. }
  148. return bSuccess;
  149. }
  150. bool FindClosestValueByRoundingDown( LONG &nValue ) const
  151. {
  152. //
  153. // Make sure we have a valid item
  154. //
  155. if (!IsValid())
  156. {
  157. return false;
  158. }
  159. if (IsRange())
  160. {
  161. //
  162. // Make sure we are in the legal range
  163. //
  164. nValue = WiaUiUtil::Min( WiaUiUtil::Max( m_ValueList[MinValue], nValue ), m_ValueList[MaxValue] );
  165. //
  166. // Divide the difference between nValue and min by nStep, then multiply by nStep to
  167. // get rid of the remainder to round down to the nearest value
  168. //
  169. nValue = m_ValueList[MinValue] + (((nValue - m_ValueList[MinValue]) / m_ValueList[StepValue]) * m_ValueList[StepValue]);
  170. return true;
  171. }
  172. else if (IsList() && m_ValueList.Size())
  173. {
  174. //
  175. // Assume the list is sorted, so we can take the first item and assume it is the minimum value
  176. //
  177. LONG nResult = m_ValueList[0];
  178. for (int i=0;i<m_ValueList.Size();i++)
  179. {
  180. if (m_ValueList[i] > nValue)
  181. {
  182. break;
  183. }
  184. nResult = m_ValueList[i];
  185. }
  186. nValue = nResult;
  187. return true;
  188. }
  189. return false;
  190. }
  191. bool FindClosestValue( LONG &nValue ) const
  192. {
  193. LONG nFloor=nValue;
  194. if (FindClosestValueByRoundingDown(nFloor))
  195. {
  196. LONG nCeiling=nFloor;
  197. if (Increment(nCeiling))
  198. {
  199. if (nValue - nFloor < nCeiling - nValue)
  200. {
  201. nValue = nFloor;
  202. return true;
  203. }
  204. else
  205. {
  206. nValue = nCeiling;
  207. return true;
  208. }
  209. }
  210. }
  211. return false;
  212. }
  213. bool IsLegalValue( LONG nValue ) const
  214. {
  215. LONG nTestValue = nValue;
  216. if (FindClosestValueByRoundingDown(nTestValue))
  217. {
  218. return (nTestValue == nValue);
  219. }
  220. return false;
  221. }
  222. int FindIndexOfItem( LONG nCurrentValue ) const
  223. {
  224. if (IsRange())
  225. {
  226. //
  227. // Make sure we are in the legal range
  228. //
  229. nCurrentValue = WiaUiUtil::Min( WiaUiUtil::Max( m_ValueList[MinValue], nCurrentValue ), m_ValueList[MaxValue] );
  230. return (nCurrentValue - m_ValueList[MinValue]) / m_ValueList[StepValue];
  231. }
  232. else if (IsList() && m_ValueList.Size())
  233. {
  234. //
  235. // Assume the list is sorted, so we can take the first item and assume it is the minimum value
  236. //
  237. for (int i=0;i<m_ValueList.Size();i++)
  238. {
  239. if (m_ValueList[i] == nCurrentValue)
  240. {
  241. return i;
  242. }
  243. }
  244. }
  245. //
  246. // returns -1 to indicate failure
  247. //
  248. return -1;
  249. }
  250. bool Increment( LONG &nCurrentValue ) const
  251. {
  252. //
  253. // Round us off. This will also take care of validation.
  254. //
  255. if (!FindClosestValueByRoundingDown( nCurrentValue ))
  256. {
  257. return false;
  258. }
  259. if (IsRange())
  260. {
  261. //
  262. // Let FindClosestValueByRoundingDown take care of making sure that we don't exceed the maximum
  263. //
  264. nCurrentValue += m_ValueList[StepValue];
  265. return FindClosestValueByRoundingDown( nCurrentValue );
  266. }
  267. else if (IsList() && m_ValueList.Size())
  268. {
  269. int nIndex = FindIndexOfItem( nCurrentValue );
  270. //
  271. // Make sure we are in the list
  272. //
  273. if (nIndex < 0)
  274. {
  275. return false;
  276. }
  277. //
  278. // Get the next value
  279. //
  280. nIndex++;
  281. //
  282. // Make sure we aren't off the end of the list
  283. //
  284. if (nIndex >= m_ValueList.Size())
  285. {
  286. nIndex = m_ValueList.Size() - 1;
  287. }
  288. //
  289. // Return it
  290. //
  291. nCurrentValue = m_ValueList[nIndex];
  292. //
  293. // Everything is OK
  294. //
  295. return true;
  296. }
  297. return false;
  298. }
  299. bool Decrement( LONG &nCurrentValue ) const
  300. {
  301. //
  302. // Round us off. This will also take care of validation.
  303. //
  304. if (!FindClosestValueByRoundingDown( nCurrentValue ))
  305. {
  306. return false;
  307. }
  308. if (IsRange())
  309. {
  310. //
  311. // Let FindClosestValueByRoundingDown take care of making sure that we don't go under the minimum
  312. //
  313. nCurrentValue -= m_ValueList[StepValue];
  314. return FindClosestValueByRoundingDown( nCurrentValue );
  315. }
  316. else if (IsList() && m_ValueList.Size())
  317. {
  318. int nIndex = FindIndexOfItem( nCurrentValue );
  319. //
  320. // Make sure we are in the list
  321. //
  322. if (nIndex < 0)
  323. {
  324. return false;
  325. }
  326. //
  327. // Get the previous value
  328. //
  329. nIndex--;
  330. //
  331. // Make sure we aren't before the beginning of the list
  332. //
  333. if (nIndex < 0)
  334. {
  335. nIndex = 0;
  336. }
  337. //
  338. // Return it
  339. //
  340. nCurrentValue = m_ValueList[nIndex];
  341. //
  342. // Everything is OK
  343. //
  344. return true;
  345. }
  346. return false;
  347. }
  348. LONG GetItemCount(void) const
  349. {
  350. if (IsList())
  351. {
  352. return m_ValueList.Size();
  353. }
  354. else if (IsRange())
  355. {
  356. //
  357. // Calculate the number of steps between the minimum and maximum
  358. //
  359. return ((m_ValueList[MaxValue] - m_ValueList[MinValue]) / m_ValueList[StepValue]) + 1;
  360. }
  361. return 0;
  362. }
  363. bool GetItemAtIndex( int nIndex, LONG &nItem ) const
  364. {
  365. if (!IsValid())
  366. {
  367. return false;
  368. }
  369. if (IsList() && nIndex >= 0 && nIndex < m_ValueList.Size())
  370. {
  371. nItem = m_ValueList[nIndex];
  372. return true;
  373. }
  374. else if (IsRange() && nIndex < GetItemCount())
  375. {
  376. //
  377. // Return the minimum + nIndex * stepvalue
  378. //
  379. nItem = m_ValueList[MinValue] + (m_ValueList[StepValue] * nIndex);
  380. return true;
  381. }
  382. return false;
  383. }
  384. bool FindIntersection( const CValidWiaSettings &Set1, const CValidWiaSettings &Set2 )
  385. {
  386. //
  387. // We are modifying ourselves, so clear all of our data
  388. //
  389. Destroy();
  390. //
  391. // If either set is invalid, no intersection
  392. //
  393. if (!Set1.IsValid() || !Set2.IsValid())
  394. {
  395. return false;
  396. }
  397. //
  398. // If either a or b is a set (or both), just add all of the items
  399. // that are legal in both to ourself and set the type to a LIST
  400. //
  401. if (Set1.IsList())
  402. {
  403. m_nType = WIA_PROP_LIST;
  404. for (int i=0;i<Set1.GetItemCount();i++)
  405. {
  406. LONG nItem;
  407. if (Set1.GetItemAtIndex(i,nItem))
  408. {
  409. if (Set2.IsLegalValue(nItem))
  410. {
  411. m_ValueList.Append(nItem);
  412. }
  413. }
  414. }
  415. //
  416. // Figure out where to get the initial value from
  417. //
  418. if (IsLegalValue(Set1.InitialValue()))
  419. {
  420. m_nInitialValue = Set1.InitialValue();
  421. }
  422. else if (IsLegalValue(Set2.InitialValue()))
  423. {
  424. m_nInitialValue = Set2.InitialValue();
  425. }
  426. else
  427. {
  428. if (!FindClosestValueByRoundingDown( m_nInitialValue ))
  429. {
  430. //
  431. // As a last resort, use the first value
  432. //
  433. GetItemAtIndex(0,m_nInitialValue);
  434. }
  435. }
  436. return (m_ValueList.Size() != 0);
  437. }
  438. else if (Set2.IsList())
  439. {
  440. m_nType = WIA_PROP_LIST;
  441. for (int i=0;i<Set2.GetItemCount();i++)
  442. {
  443. LONG nItem;
  444. if (Set2.GetItemAtIndex(i,nItem))
  445. {
  446. if (Set1.IsLegalValue(nItem))
  447. {
  448. m_ValueList.Append(nItem);
  449. }
  450. }
  451. }
  452. //
  453. // Figure out where to get the initial value from
  454. //
  455. if (IsLegalValue(Set2.InitialValue()))
  456. {
  457. m_nInitialValue = Set2.InitialValue();
  458. }
  459. else if (IsLegalValue(Set1.InitialValue()))
  460. {
  461. m_nInitialValue = Set1.InitialValue();
  462. }
  463. else
  464. {
  465. if (!FindClosestValueByRoundingDown( m_nInitialValue ))
  466. {
  467. //
  468. // As a last resort, use the first value
  469. //
  470. GetItemAtIndex(0,m_nInitialValue);
  471. }
  472. }
  473. return (m_ValueList.Size() != 0);
  474. }
  475. //
  476. // Both are ranges.
  477. // BUGBUG: I may have to actually figure out how to do this in a more sophisticated
  478. // way. Basically, I am taking the minimum of the two maximums and the maximum of the
  479. // two minimums if and only if the at least one of the minimums is in the set of the
  480. // other items and they have the same step value
  481. //
  482. else if (Set1.IsLegalValue(Set2.Min()) || Set2.IsLegalValue(Set1.Min()) && Set1.Step() == Set2.Step())
  483. {
  484. m_nType = WIA_PROP_RANGE;
  485. //
  486. // Minimum, Maximum, Step
  487. //
  488. m_ValueList.Append(WiaUiUtil::Max(Set1.Min(),Set2.Min()));
  489. m_ValueList.Append(WiaUiUtil::Min(Set1.Max(),Set2.Max()));
  490. m_ValueList.Append(Set1.Step());
  491. //
  492. // Figure out where to get the initial value from
  493. //
  494. if (IsLegalValue(Set2.InitialValue()))
  495. {
  496. m_nInitialValue = Set2.InitialValue();
  497. }
  498. else if (IsLegalValue(Set1.InitialValue()))
  499. {
  500. m_nInitialValue = Set1.InitialValue();
  501. }
  502. else
  503. {
  504. if (!FindClosestValueByRoundingDown( m_nInitialValue ))
  505. {
  506. //
  507. // As a last resort, use the first value
  508. //
  509. GetItemAtIndex(0,m_nInitialValue);
  510. }
  511. }
  512. return (m_ValueList.Size() == 3);
  513. }
  514. return true;
  515. }
  516. LONG Min(void) const
  517. {
  518. if (!IsValid())
  519. {
  520. return 0;
  521. }
  522. if (IsList())
  523. {
  524. return (m_ValueList[0]);
  525. }
  526. else if (IsRange())
  527. {
  528. return (m_ValueList[MinValue]);
  529. }
  530. return 0;
  531. }
  532. LONG Max(void) const
  533. {
  534. if (!IsValid())
  535. {
  536. return 0;
  537. }
  538. if (IsList())
  539. {
  540. return (m_ValueList[m_ValueList.Size()-1]);
  541. }
  542. else if (IsRange())
  543. {
  544. return (m_ValueList[MaxValue]);
  545. }
  546. return 0;
  547. }
  548. LONG Step(void) const
  549. {
  550. if (IsRange())
  551. {
  552. return (m_ValueList[StepValue]);
  553. }
  554. return 0;
  555. }
  556. bool IsRange(void) const
  557. {
  558. return (m_nType == WIA_PROP_RANGE);
  559. }
  560. bool IsList(void) const
  561. {
  562. return (m_nType == WIA_PROP_LIST);
  563. }
  564. static bool SetNumericPropertyOnBoundary( IUnknown *pUnknown, const PropStorageHelpers::CPropertyId &propertyName, LONG nValue )
  565. {
  566. CValidWiaSettings ValidWiaSettings;
  567. if (!ValidWiaSettings.Read( pUnknown, propertyName ))
  568. {
  569. return false;
  570. }
  571. if (!ValidWiaSettings.FindClosestValueByRoundingDown(nValue))
  572. {
  573. return false;
  574. }
  575. if (!PropStorageHelpers::SetProperty( pUnknown, propertyName, nValue ))
  576. {
  577. return false;
  578. }
  579. return true;
  580. }
  581. };
  582. #endif //__VWIASET_H_INCLUDED