home *** CD-ROM | disk | FTP | other *** search
/ ...taking it to the Macs! / ...taking it to the Macs!.iso / Extras / ActiveX Mac SDK / ActiveX SDK / Sample Controls / PictPlayer / CPictControl.cpp next >
Encoding:
Text File  |  1996-12-31  |  13.1 KB  |  632 lines  |  [TEXT/CWIE]

  1. // =================================================================================
  2. //
  3. //    CPictControl.cpp                ©1996 Microsoft Corporation All rights reserved.
  4. //
  5. // =================================================================================
  6.  
  7. #include "ocheaders.h"
  8. #include "CPictControl.h"
  9. #include "CPictControlBSC.h"
  10. #include "CCFragResource.h"
  11. #include "CCurrentResource.h"
  12.  
  13. #define    CLICK_WAIT_TIME        30
  14. #define    PICT_LINGER_TIME    5
  15. #define    CYCLE_TIME_DLOG        128
  16. #define        OK_BUTTON        1
  17. #define        CANCEL_BUTTON    2
  18. #define        LABEL_TEXT        3
  19. #define        EDIT_TEXT        4
  20. #define    MENU_ID                128
  21.  
  22. const    Uint32    DefaultIdleRefCon    = 0;
  23.  
  24. static Boolean8    FindUnusedMenuID(Int16 StartWithID, Int16 EndWithID, Int16 *FoundID);
  25. static Int16    GetPictCycleTime(Point CenterOn, Int16 CycleTime);
  26.  
  27.  
  28. #pragma mark === CPictsControl::Construction & Destruction ===
  29.  
  30. //
  31. //    CPictControl::CPictControl
  32. //
  33.  
  34. CPictControl::CPictControl(void)
  35. {
  36.     mPicts = NULL;
  37.     mCurrentPict = 1;
  38.     mCycleWaitTime = PICT_LINGER_TIME * 60;
  39.     mAutoCycle = false;
  40.     mOwnedFoci = EmptyFocusSet;
  41. }
  42.  
  43. //
  44. //    CPictControl::~CPictControl
  45. //
  46.  
  47. CPictControl::~CPictControl(void)
  48. {
  49.     if (mDataURLBuffer)
  50.     {
  51.         ::DisposeHandle(mDataURLBuffer);
  52.         mDataURLBuffer = NULL;
  53.     }
  54.  
  55.     if (mPicts)
  56.     {
  57.         for (Int16 i = 0; i < mPictCount; i++)
  58.         {
  59.             if (((*mPicts) + i)->Pic)
  60.                 ::DisposeHandle(Handle(((*mPicts) + i)->Pic));
  61.             if (((*mPicts) + i)->BSC)
  62.                 ((*mPicts) + i)->BSC->Release();
  63.         }
  64.  
  65.         ::DisposeHandle(Handle(mPicts));
  66.         mPicts = NULL;
  67.     }
  68. }
  69.  
  70.  
  71. #pragma mark === CPictControl::IControl ===
  72.  
  73. //
  74. //    CPictControl::IControl::Draw
  75. //
  76.  
  77. STDMETHODIMP
  78. CPictControl::Draw(DrawContext* inContext)
  79. {
  80.     if (inContext->DrawAspect != DVASPECT_CONTENT)
  81.         return DV_E_DVASPECT;
  82.  
  83.     ::FrameRect(&inContext->Location);
  84.  
  85.     StringPtr    ErrorMessage = NULL;
  86.     if (mPicts)
  87.     {
  88.         pictinfo    CurrentPict    = *(*mPicts + mCurrentPict - 1);
  89.         if (CurrentPict.Pic)
  90.         {
  91.             ::EraseRect(&inContext->Location);
  92.             DrawPict(inContext->Port, &inContext->Location, CurrentPict.Pic, &CurrentPict.PicRect);
  93.         }
  94.         else if (CurrentPict.BSC)
  95.             ErrorMessage = "\pPicture not loaded yet.";
  96.         else
  97.             ErrorMessage = "\pCouldn't fetch or store picture.";
  98.     }
  99.     else
  100.         ErrorMessage = "\pNo pictures as parameters.";
  101.  
  102.     if (ErrorMessage)
  103.     {
  104.         //    draw the error message
  105.         ::TextFace(bold);
  106.         ::TextFont(0);
  107.         ::TextSize(12);
  108.         ::MoveTo((inContext->Location.right + inContext->Location.left - StringWidth(ErrorMessage))/2,
  109.                 (inContext->Location.bottom + inContext->Location.top + 12)/2);
  110.         ::DrawString(ErrorMessage);
  111.     }
  112.  
  113.     return S_OK;
  114. }
  115.  
  116.  
  117. //
  118. //  CPictControl:IControl:SetFocus    
  119. //
  120. //  Since we handle focus, we override the base class method for our needs
  121. //
  122.  
  123. STDMETHODIMP
  124. CPictControl::SetFocus(FocusCommand inCommand, FocusSet inFocus)
  125. {
  126.     ErrorCode    ReturnValue = S_OK;
  127.  
  128.     //    a TakeNext or TakePrev if we don't have the focus, means take it
  129.     if ((inCommand == TakeNextCommand || inCommand == TakePrevCommand) && 
  130.         !(mOwnedFoci & inFocus))
  131.     {
  132.             mOwnedFoci = FocusSet(mOwnedFoci | inFocus);
  133.     }
  134.     //    a TakeNext or a TakePrev on a control which doesn't embed and has the focus should fail
  135.     else if (inCommand == TakeNextCommand || inCommand == TakePrevCommand)
  136.     {
  137.         ReturnValue = E_FAIL;
  138.     }
  139.     //    we're being asked/told to release our foci - always comply
  140.     else // if (Spec == ReleaseRequest || Spec == ReleaseCommand)
  141.     {
  142.         if (inFocus & mOwnedFoci != inFocus)
  143.             DebugStr("\pWhat are they doing asking to release foci we don't have?");
  144.  
  145.         mOwnedFoci = FocusSet(mOwnedFoci & ~inFocus);    //    really easy for us
  146.     }
  147.     
  148.     return ReturnValue;
  149. }
  150.  
  151.  
  152. //
  153. //    CPictControl::IControl::DoMouse    
  154. //
  155.  
  156. STDMETHODIMP
  157. CPictControl::DoMouse(MouseEventType inMouseET, PlatformEvent* inEvent)
  158. {
  159.     Boolean8    DoInval = false;
  160.     Boolean8    DoAdvance = false;
  161.  
  162.     switch (inMouseET) 
  163.     {
  164.  
  165.         case MouseDown:
  166.             {
  167.                 Boolean8    IsHoldDown;
  168.                 Int32        WaitTillTicks = inEvent->when + CLICK_WAIT_TIME;
  169.  
  170.                 while (((IsHoldDown = ::WaitMouseUp()) != 0) && ::TickCount() < WaitTillTicks)
  171.                     ;
  172.  
  173.                 if (IsHoldDown)
  174.                 {
  175.                     //    for now we'll assume that we have a popup menu
  176.                     HandlePopUpMenuClick(inEvent->where);
  177.                 }
  178.                 else if (mPictCount)
  179.                 {
  180.                     AdvancePict();
  181.  
  182.                     //    since we just advanced the picture, reset the timer
  183.                     StartIdling();
  184.                 }
  185.             }
  186.             break;
  187.     }
  188.  
  189.     return S_OK;
  190. }
  191.  
  192.  
  193. //
  194. //    CPictsControl::IControl::DoIdle    
  195. //
  196.  
  197. STDMETHODIMP
  198. CPictControl::DoIdle(Uint32 IdleRefCon)
  199. {
  200. #pragma unused(IdleRefCon)
  201.  
  202.     AdvancePict();
  203.  
  204.     return S_OK;
  205. }
  206.  
  207.  
  208. #pragma mark === CPictControl::IPersist ===
  209.  
  210. //
  211. //    CPictControl::IPersistPropertyBag::IPersistPropertyBag::Load
  212. //
  213.  
  214. STDMETHODIMP
  215. CPictControl::Load(IPropertyBag* PropertyBag, IErrorLog* ErrorLog)
  216. {
  217.     Boolean8    KeepGoing = true;
  218.     Char8        PropertyTag[10];
  219.     ErrorCode    ErrCode = S_OK;
  220.     Int16        i = 0;
  221.     VARIANT        v;
  222.  
  223.     CBaseControl::Load(PropertyBag, ErrorLog);
  224.  
  225.     //    dispose of the old url buffer if this is called multiple times
  226.     if (mDataURLBuffer)
  227.     {
  228.         ::DisposeHandle(mDataURLBuffer);
  229.         mDataURLBuffer = NULL;
  230.     }
  231.  
  232.     v.vt = VT_BSTR;
  233.     v.bstrVal = NULL;
  234.  
  235.     // try to load in the property. if we can't get it, then leave
  236.     // things at their default.
  237.     //
  238.     while (KeepGoing)
  239.     {
  240.         ::BlockMove("data", PropertyTag, 5);
  241.  
  242.         if (++i != 1)
  243.         {
  244.             Uchar8    NumString[5];
  245.             ::NumToString(i, NumString);
  246.             ::BlockMove(NumString + 1, PropertyTag + 4, *NumString);
  247.             PropertyTag[4 + *NumString] = '\0';
  248.         }
  249.  
  250.         KeepGoing = PropertyBag->Read(PropertyTag, &v, ErrorLog) == S_OK && v.bstrVal;
  251.         if (KeepGoing)
  252.         {
  253.             Uint32        DataLength = *((Uint32*) v.bstrVal);
  254.             Uint32        BufferSize;
  255.  
  256.             if (!mDataURLBuffer)
  257.             {
  258.                 BufferSize = 0;
  259.                 mDataURLBuffer = ::NewHandle(0);
  260.             }
  261.             else
  262.                 BufferSize = ::GetHandleSize(mDataURLBuffer);
  263.  
  264.             if (mDataURLBuffer)
  265.             {
  266.                 ::SetHandleSize(mDataURLBuffer, BufferSize + DataLength + 1);
  267.                 if (::MemError() != noErr)
  268.                     ErrCode = E_FAIL;
  269.             }
  270.  
  271.             if (ErrCode == S_OK)
  272.             {
  273.                 ::HLock(mDataURLBuffer);
  274.                 ::BlockMove( v.bstrVal + sizeof(Uint32), *mDataURLBuffer + BufferSize, DataLength);
  275.                 *(*mDataURLBuffer + BufferSize + DataLength) = '\0';
  276.                 ::HUnlock(mDataURLBuffer);
  277.                 CoTaskMemFree(v.bstrVal);
  278.             }
  279.         }
  280.     }
  281.  
  282.     //    if LoadTextState loaded up our data buffer then open streams
  283.     if (mDataURLBuffer)
  284.     {
  285.         Char8    *CurrentURL, *EndChar;
  286.         Int32    CurrentPosition = 0;
  287.  
  288.         ::HLock(mDataURLBuffer);
  289.         CurrentURL = *mDataURLBuffer;
  290.         EndChar = *mDataURLBuffer + ::GetHandleSize(mDataURLBuffer);
  291.  
  292.         //    start up a BSC for each url we loaded
  293.         while (CurrentURL < EndChar && ErrCode == S_OK)
  294.         {
  295.             //    if we haven't allocated a handle for picture info then allocate it
  296.             if (!mPicts)
  297.                 mPicts = (pictinfo**)::NewHandle(0);
  298.  
  299.             //    if we have allocated a handle then grow it by one
  300.             if (mPicts)
  301.             {
  302.                 ::SetHandleSize(Handle(mPicts), (mPictCount + 1) * sizeof(pictinfo));
  303.                 if (::MemError() == noErr)
  304.                 {
  305.                     pictinfo*    PictInfo;
  306.  
  307.                     ::HLock(Handle(mPicts));
  308.                     PictInfo = (*mPicts + mPictCount);
  309.                     AddRef();    // account for this pointer being sent to bsc
  310.                     PictInfo->BSC = new CPictControlBSC(this, Uint32(mPictCount + 1));
  311.                     PictInfo->Pic = NULL;
  312.                     if (PictInfo->BSC &&
  313.                         (ErrCode = PictInfo->BSC->OpenURL(mContainerSiteP, CurrentURL, false)) != S_OK)
  314.                     {
  315.                         PictInfo->BSC->Release();
  316.                         PictInfo->BSC = NULL;
  317.                     }
  318.                     ::HUnlock(Handle(mPicts));
  319.                     mPictCount++;
  320.                 }
  321.             }
  322.  
  323.             while (*CurrentURL++)
  324.                 ;
  325.             
  326.         }
  327.         ::HUnlock(mDataURLBuffer);
  328.  
  329.         //    we don't need to keep the url's around after we load them
  330.         ::DisposeHandle(mDataURLBuffer);
  331.         mDataURLBuffer = NULL;
  332.     }
  333.     
  334.     return ErrCode;
  335. }
  336.  
  337.  
  338. #pragma mark === CPictControl CBaseControl override methods ===
  339.  
  340. //
  341. //    CPictControl::StartIdling
  342. //
  343.  
  344. Boolean8
  345. CPictControl::StartIdling(void)
  346. {
  347.     Boolean8    ReturnResult = false;
  348.  
  349.     if (mAutoCycle)
  350.         ReturnResult = mContainerSiteP->SetIdleTime(mCycleWaitTime, DefaultIdleRefCon) == S_OK;
  351.  
  352.     return ReturnResult;
  353. }
  354.  
  355.  
  356. //
  357. //    CPictControl::StopIdling
  358. //
  359.  
  360. Boolean8
  361. CPictControl::StopIdling(void)
  362. {
  363.     Boolean8    ReturnResult = false;
  364.  
  365.     ReturnResult = CBaseControl::StopIdling();
  366.  
  367.     return ReturnResult;
  368. }
  369.  
  370.  
  371. #pragma mark === CPictControl private methods ===
  372.  
  373. //
  374. //    CPictControl::DrawPict
  375. //
  376.  
  377. void
  378. CPictControl::DrawPict(GrafPtr pGrafDraw, Rect* lprect, PicHandle Pic, Rect* PictRect)
  379. {
  380. #pragma unused (pGrafDraw)
  381.     Rect theRect;
  382.  
  383.     theRect.top = lprect->top;
  384.     theRect.left = lprect->left;
  385.     theRect.bottom = lprect->top + PictRect->bottom;
  386.     theRect.right = lprect->left + PictRect->right;
  387.     ::DrawPicture(Pic, &theRect);
  388. }
  389.  
  390.  
  391. //
  392. //    CPictControl::HandlePopUpMenuClick
  393. //
  394.  
  395. Boolean8
  396. CPictControl::HandlePopUpMenuClick(PlatformPoint inEventLocation)
  397. {
  398.     Int16            PopUpMenuID;
  399.  
  400.     //    find an unused menu id - or don't do anything
  401.     if (FindUnusedMenuID(MENU_ID, MENU_ID, &PopUpMenuID) ||
  402.         FindUnusedMenuID(128, 2000, &PopUpMenuID))
  403.     {
  404.         CCFragResource        CFragResourceSetter;
  405.         CCurrentResource    ResFileSetter(CFragResourceSetter.GetCFragResRefNum());
  406.         Int32                MenuSelection;
  407.         Point                GlobalPt = inEventLocation;
  408.         MenuHandle            PopUpMenuH;
  409.  
  410.         //    if there was a collision then push in the unique menu id
  411.         //    this is safe to do only because the menu is destroyed as soon
  412.         //    as we finish with it here
  413.         PopUpMenuH = ::GetMenu(MENU_ID);
  414.  
  415.         //    it is important to set the menu id ALWAYS, since the menu may have been
  416.         //    cached by the resource manager, so we get a "dirty" version with the
  417.         //    menu id used last time, which may not be valid this time
  418.         (*PopUpMenuH)->menuID = PopUpMenuID;
  419.  
  420.         //    add it into the menu bar
  421.         ::InsertMenu(PopUpMenuH, hierMenu);
  422.  
  423.         //    set the menu item state
  424.         ::SetItemMark(PopUpMenuH, 1, mAutoCycle ? checkMark : 0);
  425.             
  426.         //    do the popup thing
  427.         MenuSelection = ::PopUpMenuSelect(PopUpMenuH, GlobalPt.v, GlobalPt.h, 1);
  428.         switch (MenuSelection & 0x0000ffff)
  429.         {
  430.             case 1:
  431.                 mAutoCycle = !mAutoCycle;
  432.                 if (mAutoCycle)
  433.                 {
  434.                     AdvancePict();    //    give immediate feedback that it worked
  435.                     StartIdling();
  436.                 }
  437.                 else
  438.                     StopIdling();
  439.                 break;
  440.  
  441.             case 2:
  442.                 //    run a dialog to set m_CycleWaitTime
  443.                 Point    CenterPt = { 200, 200 };
  444.                 if ((mOwnedFoci & ModalFocus) || (mContainerSiteP->RequestFocus(true, ModalFocus) == S_OK))
  445.                 {
  446.                     mCycleWaitTime = GetPictCycleTime(CenterPt, mCycleWaitTime / 60) * 60;
  447.                     
  448.                     if (!(mOwnedFoci & ModalFocus))
  449.                         mContainerSiteP->RequestFocus(false, ModalFocus);
  450.                 }
  451.                 else
  452.                     ::SysBeep(1);
  453.                 break;
  454.  
  455.             default:
  456.                 break;
  457.         }
  458.  
  459.         //    remove the popup and release it
  460.         ::DeleteMenu(PopUpMenuID);
  461.         ::ReleaseResource( Handle(PopUpMenuH) );
  462.  
  463.     }
  464.  
  465.     return false;
  466. }
  467.  
  468.  
  469. //
  470. //    CPictControl::SetData
  471. //
  472. //    our data input friend classes call this to insert data
  473. //
  474.  
  475. void
  476. CPictControl::SetData(Handle InData, Uint32 PictIndex)
  477. {
  478.     pictinfo*    TempPictInfo;
  479.  
  480.     ::HLock(Handle(mPicts));
  481.     TempPictInfo = *mPicts + PictIndex - 1;
  482.     if (TempPictInfo->Pic)
  483.         ::DisposeHandle(Handle(TempPictInfo->Pic));
  484.     TempPictInfo->Pic = PicHandle(InData);
  485.     if (InData)
  486.         TempPictInfo->PicRect = (*(TempPictInfo->Pic))->picFrame;
  487.     if (TempPictInfo->BSC)
  488.     {
  489.         TempPictInfo->BSC->Release();
  490.         TempPictInfo->BSC = NULL;
  491.     }
  492.     ::HUnlock(Handle(mPicts));
  493.  
  494.     if (mCurrentPict == PictIndex)
  495.     {
  496.         mCurrentPict--;    //    decrement this so we can advance to it
  497.         AdvancePict();
  498.     }
  499. }
  500.  
  501.  
  502. //
  503. //    CPictControl::AdvancePict
  504. //
  505. //    advance the displayed pict
  506. //
  507.  
  508. void
  509. CPictControl::AdvancePict(void)
  510. {
  511.     Int16    PrevPict = mCurrentPict++;
  512.     //    move current picture forward
  513.     if (mCurrentPict > mPictCount)
  514.         mCurrentPict = 1;
  515.  
  516.     if (PrevPict != mCurrentPict)
  517.         mContainerSiteP->OnChange(ViewChange);
  518.  
  519.     //    adjust the size if it is needed
  520.     Boolean8    Adjusted = false;
  521.     Int32        i;
  522.     pictinfo    CurrentPict    = *(*mPicts + mCurrentPict - 1);
  523.  
  524.     if ((i = CurrentPict.PicRect.bottom - CurrentPict.PicRect.top) > mSize.v)
  525.     {
  526.         Adjusted = true;
  527.         mSize.v = i;
  528.     }
  529.  
  530.     if ((i = CurrentPict.PicRect.right - CurrentPict.PicRect.left) > mSize.h)
  531.     {
  532.         Adjusted = true;
  533.         mSize.h = i;
  534.     }
  535.  
  536.     if (Adjusted)
  537.         mContainerSiteP->RequestSizeChange(&mSize);
  538.  
  539.     //    force a redraw
  540.     InvalAllContexts();
  541. }
  542.  
  543.  
  544. #pragma mark === CPictControl Statics ===
  545.  
  546. //
  547. //    FindUnusedMenuID
  548. //
  549.  
  550. Boolean8
  551. FindUnusedMenuID(Int16 StartWithID, Int16 EndWithID, Int16 *FoundID)
  552. {
  553.     Boolean8        Found = false;
  554.  
  555.     while (StartWithID <= EndWithID && !Found)
  556.     {
  557.         if ((Found = (GetMHandle(StartWithID++) == NULL)) == true)
  558.             *FoundID = StartWithID - 1;
  559.     }
  560.  
  561.     return Found;
  562. }
  563.  
  564.  
  565. //
  566. //    GetPictCycleTime
  567. //
  568.  
  569. Int16
  570. GetPictCycleTime(Point CenterOn, Int16 CycleTime)
  571. {
  572. #pragma unused (CenterOn)
  573.     CCFragResource        CFragResourceSetter;
  574.     CCurrentResource    ResFileSetter(CFragResourceSetter.GetCFragResRefNum());
  575.     DialogPtr            DlogPtr;
  576.  
  577.     if ((DlogPtr = ::GetNewDialog(CYCLE_TIME_DLOG, NULL, (WindowPtr) -1)) != 0)
  578.     {
  579.         Boolean8        Done;
  580.         Handle            ItemHandle;
  581.         Int16            ItemHit;
  582.         Str255            TextStr;
  583.  
  584.         //    tell the dialog manager the behavior we want
  585.         ::SetDialogDefaultItem(DlogPtr, OK_BUTTON);
  586.         ::SetDialogCancelItem(DlogPtr, CANCEL_BUTTON);
  587.         ::SetDialogTracksCursor(DlogPtr, true);
  588.  
  589.         {
  590.             Rect            TRect;
  591.             Int16            Type;
  592.  
  593.             ::GetDItem(DlogPtr, EDIT_TEXT, &Type, &ItemHandle, &TRect);
  594.             ::NumToString(CycleTime, TextStr);
  595.             ::SetIText(ItemHandle, TextStr);
  596.             ::SelIText(DlogPtr, EDIT_TEXT, 0, 32767);
  597.         }
  598.  
  599.         do
  600.         {
  601.             ::ModalDialog(0, &ItemHit);
  602.             switch (ItemHit)
  603.             {
  604.                 case OK_BUTTON:
  605.                     {
  606.                         Int32    TempTime;
  607.  
  608.                         ::GetIText(ItemHandle, TextStr);
  609.                         ::StringToNum(TextStr, &TempTime);
  610.                         if (TempTime > 0)
  611.                             CycleTime = TempTime;
  612.                     }
  613.                     //    intentional fall through
  614.  
  615.                 case CANCEL_BUTTON:
  616.                     Done = true;
  617.                     break;
  618.  
  619.                 default:
  620.                     Done = false;
  621.                     break;
  622.             }
  623.         }
  624.         while (!Done);
  625.  
  626.         ::DisposeDialog(DlogPtr);
  627.     }
  628.  
  629.     return CycleTime;
  630. }
  631.  
  632.