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.

1134 lines
30 KiB

  1. #include "priv.h"
  2. #ifdef GADGET_ENABLE_GDIPLUS
  3. using namespace DirectUI;
  4. #include "Logon.h"
  5. #include "Fx.h"
  6. #include "Stub.h"
  7. #include "Super.h"
  8. const float flIGNORE = -10000.0f;
  9. const float flFadeOut = 0.50f;
  10. #define ENABLE_USEVALUEFLOW 1
  11. /***************************************************************************\
  12. *
  13. * F2T
  14. *
  15. * F2T() converts from frames to time, using a constant. This allows easily
  16. * conversion from frames in Flash or Director to time used by DirectUser.
  17. *
  18. \***************************************************************************/
  19. inline float
  20. F2T(
  21. IN int cFrames)
  22. {
  23. return cFrames / 30.0f;
  24. }
  25. inline BYTE
  26. GetAlphaByte(float fl)
  27. {
  28. if (fl <= 0.0f) {
  29. return 0;
  30. } else if (fl >= 1.0f) {
  31. return 255;
  32. } else {
  33. return (BYTE) (fl * 255.0f);
  34. }
  35. }
  36. inline float
  37. GetAlphaFloat(BYTE b)
  38. {
  39. return b * 255.0f;
  40. }
  41. /***************************************************************************\
  42. *
  43. * GetVPatternDelay
  44. *
  45. * GetVPatternDelay() computes the delay time for a standard "v-pattern" of
  46. * items that start from the middle and work outward.
  47. *
  48. \***************************************************************************/
  49. inline float
  50. GetVPatternDelay(
  51. IN float flTimeLevel,
  52. IN EFadeDirection dir,
  53. IN int idxCur,
  54. IN int cItems)
  55. {
  56. float flBase = flTimeLevel * (float) (abs(cItems / 2 - idxCur));
  57. switch (dir)
  58. {
  59. case fdIn:
  60. return flBase;
  61. case fdOut:
  62. return flTimeLevel * (abs(cItems / 2)) - flBase;
  63. default:
  64. DUIAssertForce("Unknown direction");
  65. return 0;
  66. }
  67. }
  68. //------------------------------------------------------------------------------
  69. HRESULT
  70. BuildLinearAlpha(
  71. OUT Sequence ** ppseq,
  72. OUT Interpolation ** ppip)
  73. {
  74. HRESULT hr = E_FAIL;
  75. LinearInterpolation * pip = NULL;
  76. #if ENABLE_USEVALUEFLOW
  77. ValueFlow * pflow = NULL;
  78. #else
  79. AlphaFlow * pflow = NULL;
  80. #endif
  81. Sequence * pseq = NULL;
  82. pip = LinearInterpolation::Build();
  83. if (pip == NULL) {
  84. hr = HRESULT_FROM_WIN32(GetLastError());
  85. goto ErrorExit;
  86. }
  87. #if ENABLE_USEVALUEFLOW
  88. ValueFlow::ValueFlowCI fci;
  89. ZeroMemory(&fci, sizeof(fci));
  90. fci.cbSize = sizeof(fci);
  91. pflow = ValueFlow::Build(&fci);
  92. #else
  93. Flow::FlowCI fci;
  94. ZeroMemory(&fci, sizeof(fci));
  95. fci.cbSize = sizeof(fci);
  96. pflow = AlphaFlow::Build(&fci);
  97. #endif
  98. if (pflow == NULL) {
  99. hr = HRESULT_FROM_WIN32(GetLastError());
  100. goto ErrorExit;
  101. }
  102. pseq = Sequence::Build();
  103. if (pseq == NULL) {
  104. hr = HRESULT_FROM_WIN32(GetLastError());
  105. goto ErrorExit;
  106. }
  107. pseq->SetFlow(pflow);
  108. pflow->Release();
  109. *ppseq = pseq;
  110. *ppip = pip;
  111. return S_OK;
  112. ErrorExit:
  113. if (pseq != NULL)
  114. pseq->Release();
  115. if (pflow != NULL)
  116. pflow->Release();
  117. if (pip != NULL)
  118. pip->Release();
  119. *ppseq = NULL;
  120. *ppip = NULL;
  121. return hr;
  122. }
  123. /***************************************************************************\
  124. *
  125. * class SyncVisible
  126. *
  127. * SyncVisible provides a mechansim to synchronize state between DirectUI and
  128. * DirectUser for the fading in / out effects. This allows an Element to be
  129. * marked as "visible" during the fade out and then become "not visible" when
  130. * the fade is done.
  131. *
  132. * This is important for several reasons, including not modifying the mouse
  133. * cursor when an Element becomes invisible.
  134. *
  135. \***************************************************************************/
  136. class SyncVisible
  137. {
  138. public:
  139. static void Wait(Element * pel, EventGadget * pgeOperation, UINT nMsg)
  140. {
  141. SyncVisible * psv = new SyncVisible;
  142. if (psv != NULL)
  143. {
  144. psv->_pel = pel;
  145. if (SUCCEEDED(pgeOperation->AddHandlerD(nMsg, EVENT_DELEGATE(psv, EventProc))))
  146. {
  147. // Successfully attached delegate
  148. return;
  149. }
  150. delete psv;
  151. }
  152. // Unable to create a delegate, so set now
  153. Sync(pel);
  154. }
  155. static void Wait(Element * pel, EventGadget * pgeOperation, const GUID * pguid)
  156. {
  157. MSGID nMsg;
  158. if (FindGadgetMessages(&pguid, &nMsg, 1))
  159. {
  160. SyncVisible * psv = new SyncVisible;
  161. if (psv != NULL)
  162. {
  163. psv->_nMsg = nMsg;
  164. psv->_pel = pel;
  165. psv->_pgeOperation = pgeOperation;
  166. if (SUCCEEDED(pgeOperation->AddHandlerD(nMsg, EVENT_DELEGATE(psv, EventProc))))
  167. {
  168. // Successfully attached delegate
  169. return;
  170. }
  171. delete psv;
  172. }
  173. }
  174. // Unable to create a delegate, so set now
  175. Sync(pel);
  176. }
  177. static void Sync(Element * pel)
  178. {
  179. HGADGET hgad = pel->GetDisplayNode();
  180. bool fVisible = true;
  181. if (GetGadgetStyle(hgad) & GS_BUFFERED)
  182. {
  183. BUFFER_INFO bi;
  184. bi.cbSize = sizeof(bi);
  185. bi.nMask = GBIM_ALPHA;
  186. GetGadgetBufferInfo(hgad, &bi);
  187. if (bi.bAlpha < 5)
  188. fVisible = false;
  189. }
  190. pel->SetVisible(fVisible);
  191. }
  192. protected:
  193. UINT CALLBACK EventProc(GMSG_EVENT * pmsg)
  194. {
  195. DUIAssert(GET_EVENT_DEST(pmsg) == GMF_EVENT, "Must be an event handler");
  196. Animation::CompleteEvent * pmsgC = (Animation::CompleteEvent *) pmsg;
  197. if (pmsgC->fNormal) {
  198. Sync(_pel);
  199. }
  200. _pgeOperation->RemoveHandlerD(_nMsg, EVENT_DELEGATE(this, EventProc));
  201. delete this;
  202. return GPR_NOTHANDLED;
  203. }
  204. UINT _nMsg;
  205. Element * _pel;
  206. EventGadget * _pgeOperation;
  207. };
  208. /***************************************************************************\
  209. *
  210. * FxSetAlpha
  211. *
  212. * FxSetAlpha() provides a convenient mechanism to directly set the DirectUser
  213. * "alpha" state on a Visual Gadget without modifying the DirectUI "alpha"
  214. * property.
  215. *
  216. * NOTE: Eventually, we want to synchronize these, but for now, the DirectUI
  217. * "alpha" property doesn't work with DirectUser's new (improved!) Animations
  218. * infrastructure.
  219. *
  220. \***************************************************************************/
  221. void
  222. FxSetAlpha(
  223. IN Element * pe,
  224. IN float flNewAlpha,
  225. IN float fSync)
  226. {
  227. #if ENABLE_USEVALUEFLOW
  228. pe->SetAlpha(GetAlphaByte(flNewAlpha));
  229. #else
  230. HGADGET hgad = pe->GetDisplayNode();
  231. if (flNewAlpha >= 0.97f) {
  232. // Turn off alpha
  233. SetGadgetStyle(hgad, 0, GS_BUFFERED);
  234. } else {
  235. SetGadgetStyle(hgad, GS_BUFFERED | GS_OPAQUE, GS_BUFFERED | GS_OPAQUE);
  236. BUFFER_INFO bi;
  237. ZeroMemory(&bi, sizeof(bi));
  238. bi.cbSize = sizeof(bi);
  239. bi.nMask = GBIM_ALPHA;
  240. bi.bAlpha = (BYTE) (flNewAlpha * 255.0f);
  241. SetGadgetBufferInfo(hgad, &bi);
  242. }
  243. #endif
  244. if (fSync) {
  245. SyncVisible::Sync(pe);
  246. }
  247. }
  248. /***************************************************************************\
  249. *
  250. * FxPlayLinearAlpha
  251. *
  252. * FxPlayLinearAlpha() "plays" a linear, "simple" alpha-animation on a given
  253. * Element.
  254. *
  255. \***************************************************************************/
  256. HRESULT
  257. FxPlayLinearAlpha(
  258. IN Element * pe,
  259. IN float flOldAlpha,
  260. IN float flNewAlpha,
  261. IN float flDuration,
  262. IN float flDelay)
  263. {
  264. HRESULT hr = E_FAIL;
  265. HGADGET hgad = pe->GetDisplayNode();
  266. DUIAssert(hgad != NULL, "Must have valid Gadget");
  267. Visual * pgvSubject = Visual::Cast(hgad);
  268. pgvSubject->SetStyle(GS_OPAQUE, GS_OPAQUE);
  269. //
  270. // If an old alpha is specified, have it take place immediately. We can't
  271. // use the Animation to do this because it will wait the delay.
  272. //
  273. if (flOldAlpha >= 0.0f) {
  274. FxSetAlpha(pe, flOldAlpha, false);
  275. }
  276. LinearInterpolation * pip = NULL;
  277. #if ENABLE_USEVALUEFLOW
  278. ValueFlow * pflow = NULL;
  279. ValueFlow::ValueKeyFrame kf;
  280. #else
  281. AlphaFlow * pflow = NULL;
  282. AlphaFlow::AlphaKeyFrame kf;
  283. #endif
  284. Animation * pani = NULL;
  285. pip = LinearInterpolation::Build();
  286. if (pip == NULL) {
  287. hr = HRESULT_FROM_WIN32(GetLastError());
  288. goto ErrorExit;
  289. }
  290. #if ENABLE_USEVALUEFLOW
  291. ValueFlow::ValueFlowCI fci;
  292. ZeroMemory(&fci, sizeof(fci));
  293. fci.cbSize = sizeof(fci);
  294. fci.pgvSubject = pgvSubject;
  295. fci.ppi = DirectUI::Element::AlphaProp;
  296. pflow = ValueFlow::Build(&fci);
  297. #else
  298. Flow::FlowCI fci;
  299. ZeroMemory(&fci, sizeof(fci));
  300. fci.cbSize = sizeof(fci);
  301. fci.pgvSubject = pgvSubject;
  302. pflow = AlphaFlow::Build(&fci);
  303. #endif
  304. if (pflow == NULL) {
  305. hr = HRESULT_FROM_WIN32(GetLastError());
  306. goto ErrorExit;
  307. }
  308. #if ENABLE_USEVALUEFLOW
  309. kf.cbSize = sizeof(kf);
  310. kf.ppi = DirectUI::Element::AlphaProp;
  311. kf.rv.SetInt(GetAlphaByte(flNewAlpha));
  312. #else
  313. kf.cbSize = sizeof(kf);
  314. kf.flAlpha = flNewAlpha;
  315. #endif
  316. pflow->SetKeyFrame(Flow::tEnd, &kf);
  317. Animation::AniCI aci;
  318. ZeroMemory(&aci, sizeof(aci));
  319. aci.cbSize = sizeof(aci);
  320. aci.act.flDelay = flDelay;
  321. aci.act.flDuration = flDuration;
  322. aci.act.dwPause = (DWORD) -1;
  323. aci.pgvSubject = pgvSubject;
  324. aci.pipol = pip;
  325. aci.pgflow = pflow;
  326. pani = Animation::Build(&aci);
  327. if (pani == NULL) {
  328. hr = HRESULT_FROM_WIN32(GetLastError());
  329. goto ErrorExit;
  330. }
  331. SyncVisible::Wait(pe, pani, &__uuidof(Animation::evComplete));
  332. pani->Release();
  333. pflow->Release();
  334. pip->Release();
  335. return S_OK;
  336. ErrorExit:
  337. if (pani != NULL)
  338. pani->Release();
  339. if (pflow != NULL)
  340. pflow->Release();
  341. if (pip != NULL)
  342. pip->Release();
  343. return hr;
  344. }
  345. /***************************************************************************\
  346. *
  347. * LogonFrame::FxFadeInAccounts
  348. *
  349. * FxFadeInAccounts() performs the first stage of animation:
  350. * - Fades in the user accounts
  351. * - Fades in the "options" in the bottom panel
  352. *
  353. \***************************************************************************/
  354. HRESULT
  355. LogonFrame::FxStartup()
  356. {
  357. HRESULT hr = E_FAIL, hrT;
  358. hrT = FxFadeAccounts(fdIn);
  359. if (FAILED(hrT))
  360. hr = hrT;
  361. //
  362. // Fade in the "bottom pane" info
  363. //
  364. hrT = FxPlayLinearAlpha(_peOptions, 0.0f, 1.0f, F2T(16), F2T(32));
  365. if (FAILED(hrT))
  366. hr = hrT;
  367. return hr;
  368. }
  369. /***************************************************************************\
  370. *
  371. * LogonFrame::FxFadeAccounts
  372. *
  373. * FxFadeAccounts() fades the user accounts using a "v-delay" pattern
  374. *
  375. \***************************************************************************/
  376. HRESULT
  377. LogonFrame::FxFadeAccounts(
  378. IN EFadeDirection dir,
  379. IN float flCommonDelay)
  380. {
  381. HRESULT hr = E_FAIL;
  382. Element * peSelection = NULL;
  383. float flOldAlpha, flNewAlpha, flTimeLevel;
  384. switch (dir)
  385. {
  386. case fdIn:
  387. // Fading accounts in (startup)
  388. flOldAlpha = 0.0f;
  389. flNewAlpha = 1.0f;
  390. flTimeLevel = F2T(5);
  391. break;
  392. case fdOut:
  393. // Fading accounts out (login)
  394. flOldAlpha = flIGNORE;
  395. flNewAlpha = 0.0f;
  396. flTimeLevel = F2T(5);
  397. peSelection = _peAccountList->GetSelection();
  398. break;
  399. default:
  400. DUIAssertForce("Unknown direction");
  401. return E_FAIL;
  402. }
  403. Value* pvChildren;
  404. ElementList* peList = _peAccountList->GetChildren(&pvChildren);
  405. if (peList)
  406. {
  407. hr = S_OK;
  408. LogonAccount* peAccount;
  409. int cAccounts = peList->GetSize();
  410. for (int i = 0; i < cAccounts; i++)
  411. {
  412. peAccount = (LogonAccount*)peList->GetItem(i);
  413. //
  414. // When fading out, we don't want to fade the selected item
  415. //
  416. if ((dir == fdOut) && (peAccount == peSelection))
  417. {
  418. continue;
  419. }
  420. float flDuration = F2T(15);
  421. float flDelay = GetVPatternDelay(flTimeLevel, dir, i, cAccounts) + flCommonDelay;
  422. HRESULT hrT = FxPlayLinearAlpha(peAccount, flOldAlpha, flNewAlpha, flDuration, flDelay);
  423. if (FAILED(hrT)) {
  424. hr = hrT;
  425. }
  426. }
  427. }
  428. pvChildren->Release();
  429. return hr;
  430. }
  431. /***************************************************************************\
  432. *
  433. * LogonFrame::FxLogUserOn
  434. *
  435. * FxLogUserOn() performs the login stage of animation:
  436. * - Fade out Password field, "Type your password", "go" & "help" button
  437. * - WAIT
  438. * - Fade out scroll-bar
  439. * - WAIT
  440. * - Fade out other accounts (outside to selection), fade out "Click on your user..."
  441. * - WAIT
  442. * - Fade out of selection bitmap
  443. * - Scroll-up of Icon / Name
  444. * - Fade in "Logging in to Microsoft Windows"
  445. * - Fade out "Turn off..." and "To manage or change accounts..."
  446. *
  447. \***************************************************************************/
  448. HRESULT
  449. LogonFrame::FxLogUserOn(LogonAccount * pla)
  450. {
  451. HRESULT hr = S_OK;
  452. pla->FxLogUserOn();
  453. FxFadeAccounts(fdOut);
  454. // Fade out the "bottom pane" info
  455. FxPlayLinearAlpha(_peOptions, flIGNORE, 0.0f, F2T(10), F2T(65));
  456. GMA_ACTION act;
  457. ZeroMemory(&act, sizeof(act));
  458. act.cbSize = sizeof(act);
  459. act.flDelay = F2T(50);
  460. act.pvData = this;
  461. act.pfnProc = OnLoginCenterStage;
  462. CreateAction(&act);
  463. return hr;
  464. }
  465. /***************************************************************************\
  466. *
  467. * LogonFrame::OnLoginCenterStage
  468. *
  469. * OnLoginCenterStage() is called after everything has faded away, and we
  470. * are in the final steps.
  471. *
  472. \***************************************************************************/
  473. void CALLBACK
  474. LogonFrame::OnLoginCenterStage(GMA_ACTIONINFO * pmai)
  475. {
  476. if (!pmai->fFinished) {
  477. return;
  478. }
  479. LogonFrame * plf = (LogonFrame *) pmai->pvData;
  480. // Set keyfocus back to frame so it isn't pushed anywhere when controls are removed.
  481. // This will also cause a remove of the password panel from the current account
  482. plf->SetKeyFocus();
  483. // Clear list of logon accounts except the one logging on
  484. Value* pvChildren;
  485. ElementList* peList = plf->_peAccountList->GetChildren(&pvChildren);
  486. if (peList)
  487. {
  488. LogonAccount* peAccount;
  489. for (UINT i = 0; i < peList->GetSize(); i++)
  490. {
  491. peAccount = (LogonAccount*)peList->GetItem(i);
  492. if (peAccount->GetLogonState() == LS_Denied)
  493. {
  494. peAccount->SetLayoutPos(LP_None);
  495. }
  496. }
  497. }
  498. pvChildren->Release();
  499. }
  500. /***************************************************************************\
  501. *
  502. * LogonAccount::FxLogUserOn
  503. *
  504. * FxLogUserOn() performs the login stage of animation for the selected
  505. * account.
  506. * - Fade out Password field, "Type your password", "go" & "help" button
  507. *
  508. \***************************************************************************/
  509. HRESULT
  510. LogonAccount::FxLogUserOn()
  511. {
  512. HRESULT hr = S_OK;
  513. // Need to manually hide the edit control
  514. HideEdit();
  515. // Fade out the password panel
  516. FxPlayLinearAlpha(_pePwdPanel, 1.0f, 0.0f, F2T(10));
  517. return hr;
  518. }
  519. /***************************************************************************\
  520. *
  521. * LogonAccountList::FxMouseWithin
  522. *
  523. * FxMouseWithin() performs animations when the mouse enters or leaves the
  524. * account list.
  525. *
  526. \***************************************************************************/
  527. HRESULT
  528. LogonAccountList::FxMouseWithin(
  529. IN EFadeDirection dir)
  530. {
  531. HRESULT hr = E_FAIL;
  532. float flOldAlpha, flNewAlpha, flDuration;
  533. switch (dir)
  534. {
  535. case fdIn:
  536. // Entering list, so fade non-mouse-within accounts out
  537. flOldAlpha = 1.00f;
  538. flNewAlpha = flFadeOut;
  539. flDuration = F2T(5);
  540. break;
  541. case fdOut:
  542. // Leaving list, so fade non-mouse-within accounts in
  543. flOldAlpha = flIGNORE;
  544. flNewAlpha = 1.00f;
  545. flDuration = F2T(5);
  546. break;
  547. default:
  548. DUIAssertForce("Unknown direction");
  549. return E_FAIL;
  550. }
  551. Value* pvChildren;
  552. ElementList* peList = GetChildren(&pvChildren);
  553. if (peList)
  554. {
  555. hr = S_OK;
  556. LogonAccount* peAccount;
  557. int cAccounts = peList->GetSize();
  558. for (int i = 0; i < cAccounts; i++)
  559. {
  560. peAccount = (LogonAccount*)peList->GetItem(i);
  561. if (peAccount->GetLogonState() == LS_Pending)
  562. {
  563. //
  564. // Animations to use before login
  565. //
  566. if (peAccount->GetMouseWithin())
  567. {
  568. //
  569. // Mouse is within this child. We need to special case this
  570. // node since the list is notified of the MouseWithin property
  571. // change AFTER the child itself is. If we didn't special case
  572. // this, we would fade the MouseWithin child out with the rest
  573. // of its siblings.
  574. //
  575. FxSetAlpha(peAccount, 1.0f, true);
  576. }
  577. else
  578. {
  579. //
  580. // Mouse was not within this child, so apply the defaults
  581. //
  582. HRESULT hrT = FxPlayLinearAlpha(peAccount, flOldAlpha, flNewAlpha, flDuration);
  583. if (FAILED(hrT)) {
  584. hr = hrT;
  585. }
  586. }
  587. }
  588. }
  589. }
  590. pvChildren->Release();
  591. return hr;
  592. }
  593. /***************************************************************************\
  594. *
  595. * LogonAccount::FxMouseWithin
  596. *
  597. * FxMouseWithin() performs animations when the mouse enters an individual
  598. * account item.
  599. *
  600. \***************************************************************************/
  601. HRESULT
  602. LogonAccount::FxMouseWithin(
  603. IN EFadeDirection dir)
  604. {
  605. HRESULT hr = S_OK;
  606. //
  607. // Only apply fades when we are not actually logging in. This is important
  608. // because we kick off an entire set of animations that could be overridden
  609. // if we don't respect this. When we log in, we change each of the
  610. // accounts from LS_Pending.
  611. //
  612. switch (dir)
  613. {
  614. case fdIn:
  615. // Entering account, so fade non-mouse-within accounts out
  616. if (_fHasPwdPanel)
  617. ShowEdit();
  618. if (GetLogonState() == LS_Pending)
  619. hr = FxPlayLinearAlpha(this, flIGNORE, 1.0f, F2T(3));
  620. break;
  621. case fdOut:
  622. // Leaving account, so fade non-mouse-within accounts in
  623. if (_fHasPwdPanel)
  624. HideEdit();
  625. if (GetLogonState() == LS_Pending)
  626. hr = FxPlayLinearAlpha(this, flIGNORE, flFadeOut, F2T(10));
  627. break;
  628. default:
  629. DUIAssertForce("Unknown direction");
  630. return E_FAIL;
  631. }
  632. return hr;
  633. }
  634. /***************************************************************************\
  635. *****************************************************************************
  636. *
  637. * helper Compute() functions
  638. *
  639. *****************************************************************************
  640. \***************************************************************************/
  641. //------------------------------------------------------------------------------
  642. inline int
  643. Round(float f)
  644. {
  645. return (int) (f + 0.5);
  646. }
  647. //------------------------------------------------------------------------------
  648. inline int
  649. Compute(Interpolation * pipol, float flProgress, int nStart, int nEnd)
  650. {
  651. return Round(pipol->Compute(flProgress, (float) nStart, (float) nEnd));
  652. }
  653. //------------------------------------------------------------------------------
  654. inline bool
  655. Compute(Interpolation * pipol, float flProgress, bool fStart, bool fEnd)
  656. {
  657. return (pipol->Compute(flProgress, 0.0f, 1.0f) < 0.5f) ? fStart : fEnd;
  658. }
  659. //------------------------------------------------------------------------------
  660. POINT
  661. Compute(Interpolation * pipol, float flProgress, const POINT * pptStart, const POINT * pptEnd)
  662. {
  663. POINT pt;
  664. pt.x = Compute(pipol, flProgress, pptStart->x, pptEnd->x);
  665. pt.y = Compute(pipol, flProgress, pptStart->y, pptEnd->y);
  666. return pt;
  667. }
  668. //------------------------------------------------------------------------------
  669. SIZE
  670. Compute(Interpolation * pipol, float flProgress, const SIZE * psizeStart, const SIZE * psizeEnd)
  671. {
  672. SIZE size;
  673. size.cx = Compute(pipol, flProgress, psizeStart->cx, psizeEnd->cx);
  674. size.cy = Compute(pipol, flProgress, psizeStart->cy, psizeEnd->cy);
  675. return size;
  676. }
  677. //------------------------------------------------------------------------------
  678. RECT
  679. Compute(Interpolation * pipol, float flProgress, const RECT * prcStart, const RECT * prcEnd)
  680. {
  681. RECT rc;
  682. rc.left = Compute(pipol, flProgress, prcStart->left, prcEnd->left);
  683. rc.top = Compute(pipol, flProgress, prcStart->top, prcEnd->top);
  684. rc.right = Compute(pipol, flProgress, prcStart->right, prcEnd->right);
  685. rc.bottom = Compute(pipol, flProgress, prcStart->bottom, prcEnd->bottom);
  686. return rc;
  687. }
  688. //------------------------------------------------------------------------------
  689. COLORREF
  690. Compute(Interpolation * pipol, float flProgress, COLORREF crStart, COLORREF crEnd)
  691. {
  692. int nAlpha = Compute(pipol, flProgress, GetAValue(crStart), GetAValue(crEnd));
  693. int nRed = Compute(pipol, flProgress, GetRValue(crStart), GetRValue(crEnd));
  694. int nGreen = Compute(pipol, flProgress, GetGValue(crStart), GetGValue(crEnd));
  695. int nBlue = Compute(pipol, flProgress, GetBValue(crStart), GetBValue(crEnd));
  696. return ARGB(nAlpha, nRed, nGreen, nBlue);
  697. }
  698. //------------------------------------------------------------------------------
  699. DirectUI::Color
  700. Compute(Interpolation * pipol, float flProgress, const DirectUI::Color * pclrStart, const DirectUI::Color * pclrEnd)
  701. {
  702. DirectUI::Color clr;
  703. clr.dType = pclrStart->dType;
  704. clr.cr = Compute(pipol, flProgress, pclrStart->cr, pclrEnd->cr);
  705. switch (clr.dType)
  706. {
  707. case COLORTYPE_TriHGradient:
  708. case COLORTYPE_TriVGradient:
  709. clr.cr3 = Compute(pipol, flProgress, pclrStart->cr, pclrEnd->cr);
  710. // Fall through
  711. case COLORTYPE_HGradient:
  712. case COLORTYPE_VGradient:
  713. clr.cr2 = Compute(pipol, flProgress, pclrStart->cr, pclrEnd->cr);
  714. }
  715. return clr;
  716. }
  717. //------------------------------------------------------------------------------
  718. inline float
  719. Compute(Interpolation * pipol, float flProgress, float flStart, float flEnd)
  720. {
  721. return pipol->Compute(flProgress, flStart, flEnd);
  722. }
  723. /***************************************************************************\
  724. *****************************************************************************
  725. *
  726. * class DuiValueFlow
  727. *
  728. *****************************************************************************
  729. \***************************************************************************/
  730. class DuiValueFlow : public ValueFlowImpl<DuiValueFlow, SFlow>
  731. {
  732. // Construction
  733. public:
  734. static HRESULT InitClass();
  735. HRESULT PostBuild(DUser::Gadget::ConstructInfo * pci);
  736. // Operations
  737. public:
  738. // Public API:
  739. public:
  740. dapi PRID ApiGetPRID() { return s_prid; }
  741. dapi HRESULT ApiGetKeyFrame(Flow::ETime time, DUser::KeyFrame * pkf);
  742. dapi HRESULT ApiSetKeyFrame(Flow::ETime time, const DUser::KeyFrame * pkf);
  743. dapi void ApiOnReset(Visual * pgvSubject);
  744. dapi void ApiOnAction(Visual * pgvSubject, Interpolation * pipol, float flProgress);
  745. // Implementaton
  746. protected:
  747. Element * GetElement(Visual * pgvSubject);
  748. // Data
  749. public:
  750. static PRID s_prid;
  751. protected:
  752. DirectUI::PropertyInfo*
  753. m_ppi;
  754. ValueFlow::RawValue
  755. m_rvStart;
  756. ValueFlow::RawValue
  757. m_rvEnd;
  758. };
  759. /***************************************************************************\
  760. *****************************************************************************
  761. *
  762. * class DuiValueFlow
  763. *
  764. *****************************************************************************
  765. \***************************************************************************/
  766. PRID DuiValueFlow::s_prid = 0;
  767. const GUID guidValueFlow = { 0xad9f0bd4, 0x1610, 0x47f3, { 0xba, 0xc9, 0x2c, 0x82, 0xe, 0x35, 0x2, 0xdf } }; // {AD9F0BD4-1610-47f3-BAC9-2C820E3502DF}
  768. IMPLEMENT_GUTS_ValueFlow(DuiValueFlow, SFlow);
  769. //------------------------------------------------------------------------------
  770. HRESULT
  771. DuiValueFlow::InitClass()
  772. {
  773. s_prid = RegisterGadgetProperty(&guidValueFlow);
  774. return s_prid != 0 ? S_OK : (HRESULT) GetLastError();
  775. }
  776. //------------------------------------------------------------------------------
  777. HRESULT
  778. DuiValueFlow::PostBuild(
  779. IN DUser::Gadget::ConstructInfo * pci)
  780. {
  781. //
  782. // Get the information from the Gadget / Element
  783. //
  784. ValueFlow::ValueFlowCI * pDesc = static_cast<ValueFlow::ValueFlowCI *>(pci);
  785. DirectUI::Element * pel = GetElement(pDesc->pgvSubject);
  786. if ((pDesc != NULL) && (pel != NULL)) {
  787. m_ppi = pDesc->ppi;
  788. if (m_ppi != NULL) {
  789. DirectUI::Value * pvSrc = pel->GetValue(m_ppi, PI_Specified);
  790. DUIAssert(pvSrc != Value::pvUnset, "Value must be defined");
  791. m_rvStart.SetValue(pvSrc);
  792. m_rvEnd = m_rvStart;
  793. pvSrc->Release();
  794. }
  795. }
  796. #if DEBUG_TRACECREATION
  797. TRACE("DuiValueFlow 0x%p on 0x%p initialized\n", pgvSubject, this);
  798. #endif // DEBUG_TRACECREATION
  799. return S_OK;
  800. }
  801. //------------------------------------------------------------------------------
  802. HRESULT
  803. DuiValueFlow::ApiGetKeyFrame(Flow::ETime time, DUser::KeyFrame * pkf)
  804. {
  805. if (pkf->cbSize != sizeof(ValueFlow::ValueKeyFrame)) {
  806. return E_INVALIDARG;
  807. }
  808. ValueFlow::ValueKeyFrame * pkfV = static_cast<ValueFlow::ValueKeyFrame *>(pkf);
  809. switch (time)
  810. {
  811. case Flow::tBegin:
  812. pkfV->ppi = m_ppi;
  813. pkfV->rv = m_rvStart;
  814. return S_OK;
  815. case Flow::tEnd:
  816. pkfV->ppi = m_ppi;
  817. pkfV->rv = m_rvEnd;
  818. return S_OK;
  819. default:
  820. return E_INVALIDARG;
  821. }
  822. }
  823. //------------------------------------------------------------------------------
  824. HRESULT
  825. DuiValueFlow::ApiSetKeyFrame(Flow::ETime time, const DUser::KeyFrame * pkf)
  826. {
  827. if (pkf->cbSize != sizeof(ValueFlow::ValueKeyFrame)) {
  828. return E_INVALIDARG;
  829. }
  830. const ValueFlow::ValueKeyFrame * pkfV = static_cast<const ValueFlow::ValueKeyFrame *>(pkf);
  831. switch (time)
  832. {
  833. case Flow::tBegin:
  834. m_ppi = pkfV->ppi;
  835. m_rvStart = pkfV->rv;
  836. return S_OK;
  837. case Flow::tEnd:
  838. m_ppi = pkfV->ppi;
  839. m_rvEnd = pkfV->rv;
  840. return S_OK;
  841. default:
  842. return E_INVALIDARG;
  843. }
  844. }
  845. //------------------------------------------------------------------------------
  846. void
  847. DuiValueFlow::ApiOnReset(Visual * pgvSubject)
  848. {
  849. DirectUI::Element * pel;
  850. if ((m_ppi != NULL) && ((pel = GetElement(pgvSubject)) != NULL)) {
  851. DirectUI::Value * pvNew = NULL;
  852. if (SUCCEEDED(m_rvStart.GetValue(&pvNew))) {
  853. DUIAssert(pvNew != NULL, "Must have valid value");
  854. pel->SetValue(m_ppi, PI_Local, pvNew);
  855. pvNew->Release();
  856. }
  857. }
  858. }
  859. //------------------------------------------------------------------------------
  860. void
  861. DuiValueFlow::ApiOnAction(Visual * pgvSubject, Interpolation * pipol, float flProgress)
  862. {
  863. DirectUI::Element * pel;
  864. if ((m_ppi != NULL) && ((pel = GetElement(pgvSubject)) != NULL)) {
  865. if (m_rvStart.GetType() != m_rvEnd.GetType()) {
  866. DUITrace("DuiValueFlow: Start and end value types do not match\n");
  867. } else {
  868. ValueFlow::RawValue rvCompute;
  869. BOOL fValid = TRUE;
  870. switch (m_rvStart.GetType())
  871. {
  872. case DUIV_INT:
  873. rvCompute.SetInt(Compute(pipol, flProgress, m_rvStart.GetInt(), m_rvEnd.GetInt()));
  874. break;
  875. case DUIV_BOOL:
  876. rvCompute.SetBool(Compute(pipol, flProgress, m_rvStart.GetBool(), m_rvEnd.GetBool()));
  877. break;
  878. case DUIV_POINT:
  879. rvCompute.SetPoint(Compute(pipol, flProgress, m_rvStart.GetPoint(), m_rvEnd.GetPoint()));
  880. break;
  881. case DUIV_SIZE:
  882. rvCompute.SetSize(Compute(pipol, flProgress, m_rvStart.GetSize(), m_rvEnd.GetSize()));
  883. break;
  884. case DUIV_RECT:
  885. rvCompute.SetRect(Compute(pipol, flProgress, m_rvStart.GetRect(), m_rvEnd.GetRect()));
  886. break;
  887. case DUIV_COLOR:
  888. rvCompute.SetColor(Compute(pipol, flProgress, m_rvStart.GetColor(), m_rvEnd.GetColor()));
  889. break;
  890. default:
  891. ASSERT(0 && "Unknown value type");
  892. fValid = FALSE;
  893. }
  894. if (fValid) {
  895. DirectUI::Value * pvNew = NULL;
  896. if (SUCCEEDED(rvCompute.GetValue(&pvNew))) {
  897. DUIAssert(pvNew != NULL, "Must have valid value");
  898. pel->SetValue(m_ppi, PI_Local, pvNew);
  899. pvNew->Release();
  900. }
  901. }
  902. }
  903. }
  904. }
  905. //------------------------------------------------------------------------------
  906. Element *
  907. DuiValueFlow::GetElement(Visual * pgvSubject)
  908. {
  909. Element * pel = NULL;
  910. if (pgvSubject != NULL) {
  911. HGADGET hgadSubject = pgvSubject->GetHandle();
  912. DUIAssert(hgadSubject != NULL, "Must have valid handle");
  913. pel = DirectUI::ElementFromGadget(hgadSubject);
  914. DUIAssert(pel != NULL, "Must have a valid DirectUI Element");
  915. }
  916. return pel;
  917. }
  918. //------------------------------------------------------------------------------
  919. HRESULT FxInitGuts()
  920. {
  921. if (!DuiValueFlow::InitValueFlow()) {
  922. return E_OUTOFMEMORY;
  923. }
  924. return S_OK;
  925. }
  926. #endif // GADGET_ENABLE_GDIPLUS