home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-12-20 | 13.1 KB | 555 lines | [TEXT/????] |
- // =================================================================================
- //
- // CListBoxControl.cpp ©1996 Microsoft Corporation All rights reserved.
- //
- // =================================================================================
-
- #include "ocheaders.h"
- #include "CListBoxControl.h"
-
-
- /************* Local ListBox defines ****************/
- #define SCROLL_BAR_WIDTH 15
- #define KEY_UPARROW 0x1E
- #define KEY_DOWNARROW 0x1F
-
- const Uint32 DataAvailableIdleRefCon = 1;
- const Int32 DataAvailableIdleTime = 30; // half a second
-
-
- #pragma mark === CListBoxControl::Construction & Destruction ===
-
- //
- // CListBoxControl::CListBoxControl
- //
-
- CListBoxControl::CListBoxControl(void)
- {
- mListH = NULL;
- mData = NULL;
- mLoaded = false;
- mItemCount = 0;
- mItemInProgressIndex = 0;
- mSelectedCell.h = -1;
- mSelectedCell.v = -1;
- }
-
- //
- // CListBoxControl::~CListBoxControl
- //
-
- CListBoxControl::~CListBoxControl()
- {
- if (mListH)
- ::LDispose(mListH);
- if (mData)
- ::DisposeHandle( Handle(mData) );
- }
-
-
- #pragma mark === CListBoxControl::IUnknown ===
-
- //
- // CListBoxControl::IUnknown::QueryInterface
- //
- // Returns a pointer to the specified interface on a component to which a
- // client currently holds an interface pointer.
- //
- STDMETHODIMP
- CListBoxControl::QueryInterface(REFIID inRefID, void** outObj)
- {
- if ( inRefID == IID_IBindStatusCallback )
- return CBaseBindStatusCallback::QueryInterface(inRefID, outObj);
- else
- return CBaseControl::QueryInterface(inRefID, outObj);
- }
-
-
- #pragma mark === CListBoxControl::IControl ===
-
- //
- // CListBoxControl::IControl::Draw
- //
-
- STDMETHODIMP
- CListBoxControl::Draw(DrawContext* inContext)
- {
- Rect ListRect;
-
- if (inContext->DrawAspect != DVASPECT_CONTENT)
- return DV_E_DVASPECT;
-
- // Set the font to what we want
- TextFont(1);
- TextFace(0);
- TextMode(srcCopy);
- TextSize(12);
-
- // if we have the focus, show the user
- if ( mOwnedFoci & KeyboardFocus )
- {
- ::PenSize(2, 2);
- ::FrameRect(&inContext->Location);
- ::PenSize(1, 1);
- }
-
- // Now frame the list
- ::SetRect(&ListRect, inContext->Location.left + 4, inContext->Location.top + 4, inContext->Location.right - 4 - SCROLL_BAR_WIDTH, inContext->Location.bottom - 4);
- ::FrameRect(&ListRect);
-
- // if we don't have a list handle yet, then create it
- if (!mListH)
- {
- Point CellSize;
- Rect DataBounds;
-
- ::SetRect(&DataBounds, 0, 0, 1, 0);
- ::SetRect(&ListRect, inContext->Location.left + 5, inContext->Location.top + 5, inContext->Location.right - 5 - SCROLL_BAR_WIDTH, inContext->Location.bottom - 5);
- SetPt( &CellSize, ListRect.right - ListRect.left, 14);
- mListH = ::LNew(&ListRect, &DataBounds, CellSize, 0, inContext->Port, true, false, false, true);
- }
-
- // if there is a list handle, populate it if necessary and draw it
- if (mListH)
- {
- listitemdata *ListItem;
- Int16 i;
-
- // Populate the list manager list from our data for items that haven't been inserted
- HLock( Handle( mData ));
- ::LDoDraw(false, mListH);
- for (i = 0, ListItem = *mData; i < mItemCount; i++, ListItem++)
- {
- if (!ListItem->Inserted)
- {
- Cell NewCell;
- NewCell.h = 0;
- NewCell.v = i;
- ::LAddRow(1, i, mListH);
- ::LSetCell(&ListItem->Data[1], ListItem->Data[0], NewCell, mListH);
- ListItem->Inserted = true;
- }
- }
- ::LDoDraw(true, mListH);
- HUnlock( Handle( mData ));
-
- // Draw the list
- LUpdate(((WindowPtr) inContext->Port)->visRgn, mListH);
-
- // if we don't have the focus, make sure the scroll bars are white
- if ( !(mOwnedFoci & KeyboardFocus) )
- {
- Rect ScrollRect;
-
- SetRect(&ScrollRect, inContext->Location.right - 5 - SCROLL_BAR_WIDTH, inContext->Location.top + 4, inContext->Location.right - 4, inContext->Location.bottom-4);
- EraseRect(&ScrollRect);
- FrameRect(&ScrollRect);
- }
-
- mChanged = false;
- }
-
- return S_OK;
- }
-
-
- //
- // CListBoxControl::IControl::DoMouse
- //
-
- STDMETHODIMP
- CListBoxControl::DoMouse(MouseEventType inMouseET, PlatformEvent* inEvent)
- {
- DrawContext Context = {BeginPortType};
- PlatformPoint localPt;
- Point Cell = {0, 0};
- Boolean8 acquired = false;
-
- if (inMouseET == MouseDown)
- {
- if (!(mOwnedFoci & KeyboardFocus))
- {
- if (mContainerSiteP->RequestFocus(true, KeyboardFocus) == S_OK)
- {
- mOwnedFoci = FocusSet(mOwnedFoci | KeyboardFocus);
- acquired = true;
- }
- }
-
- mContainerSiteP->AcquireContext(mActiveContext->GetContextID(), &Context);
-
- TextFont(1);
- TextFace(0);
- TextMode(srcCopy);
- TextSize(12);
-
- localPt = inEvent->where;
- ::GlobalToLocal(&localPt);
-
- if (::LClick(localPt, 0, mListH))
- ::SysBeep(1);
-
- // If we've acquired the keyboard focus and we have a saved selection,
- // do we need to restore it?
- if (acquired &&
- (mSelectedCell.h != -1 && mSelectedCell.v != -1))
- {
- // If the click didn't select an item in the list, restore the saved selection
- if (!(::LGetSelect(true, &Cell, mListH)))
- ::LSetSelect(true, mSelectedCell, mListH); // select cell
- mSelectedCell.h = -1;
- mSelectedCell.v = -1;
- }
-
- // If we don't have the focus, we have a saved selection, and the click
- // selected an item in the list, update the saved selection (used when
- // we receive the expected SetFocus call).
- if (!(mOwnedFoci & KeyboardFocus) &&
- (mSelectedCell.h != -1 && mSelectedCell.v != -1) &&
- ::LGetSelect(true, &Cell, mListH))
- {
- mSelectedCell = Cell;
- }
-
- mContainerSiteP->ReleaseContext(&Context);
- }
-
- return S_OK;
- }
-
-
- //
- // CListBoxControl::IControl::DoKey
- //
-
- STDMETHODIMP
- CListBoxControl::DoKey(KeyEventType inKeyET, Char8 inChar, PlatformEvent* inEvent)
- {
- #pragma unused (inEvent)
- DrawContext Context = {BeginPortType};
-
- mContainerSiteP->AcquireContext(mActiveContext->GetContextID(), &Context);
-
- TextFont(1);
- TextFace(0);
- TextMode(srcCopy);
- TextSize(12);
-
- if ((inKeyET == KeyDown) || (inKeyET == AutoKey))
- {
- // if we have the focus, handle the key down
- if ( mOwnedFoci & KeyboardFocus )
- {
- Boolean BeyondBounds = false;
- Boolean UnSelectCell = true;
- Point InCell = {0, 0};
- Point OutCell = {0, 0};
-
- // We only care about up and down arrow keypresses
- if ( inChar == KEY_UPARROW || inChar == KEY_DOWNARROW )
- {
- // if we find a selection, move it in the appropriate direction
- if ( ::LGetSelect(true, &InCell, mListH) )
- {
- OutCell = InCell;
- // Turn on the selection in the up or down cell
- switch ( inChar )
- {
- case KEY_UPARROW:
- if ( OutCell.v > 0 )
- OutCell.v --;
- else
- BeyondBounds = true;
- break;
-
- case KEY_DOWNARROW:
- if ( OutCell.v < (mItemCount-1) )
- OutCell.v ++;
- else
- BeyondBounds = true;
- break;
- }
- }
- // no selection means that we go by the arrows for the first one
- else
- {
- UnSelectCell = false;
- switch ( inChar )
- {
- case KEY_UPARROW:
- OutCell.v = 0;
- break;
- case KEY_DOWNARROW:
- OutCell.v = mItemCount - 1;
- break;
- }
- }
-
- // handle exit chores of changing selection
- if (!BeyondBounds && UnSelectCell)
- ::LSetSelect(false, InCell, mListH);
- if (!BeyondBounds)
- {
- ::LSetSelect(true, OutCell, mListH);
- ::LAutoScroll(mListH);
- }
- else
- ::SysBeep(1);
- }
- }
- }
-
- mContainerSiteP->ReleaseContext(&Context);
-
- return S_OK;
- }
-
-
- //
- // CListBoxControl::IControl::DoIdle
- //
-
- STDMETHODIMP
- CListBoxControl::DoIdle(Uint32 inIdleRefCon)
- {
- #pragma unused (inIdleRefCon)
- if (inIdleRefCon == DataAvailableIdleRefCon)
- {
- DrawContext Context = {BeginPortType};
-
- if (mChanged)
- {
- if (mContainerSiteP->AcquireContext(mActiveContext->GetContextID(), &Context) == S_OK)
- {
- InvalRect(&Context.Location);
- mContainerSiteP->ReleaseContext(&Context);
- }
- }
-
- if (mLoaded)
- mContainerSiteP->SetIdleTime(RemoveIdler, DataAvailableIdleRefCon);
- }
-
- return S_OK;
- }
-
-
- //=--------------------------------------------------------------------------=
- // CBaseControl:IControl:SetFocus
- //
- // Since we handle focus, we override the base class method for our needs
- //
- //=--------------------------------------------------------------------------=
- STDMETHODIMP
- CListBoxControl::SetFocus(FocusCommand inCommand, FocusSet inFocus)
- {
- DrawContext Context = {BeginPortType};
- ErrorCode ReturnValue = S_OK;
- FocusSet InOwnedFoci = mOwnedFoci;
-
- // a TakeNext or TakePrev if we don't have the focus, means take it
- if ((inCommand == TakeNextCommand || inCommand == TakePrevCommand) && !mOwnedFoci)
- {
- // if the container is offering us the one focus we want, take all of them
- if (inFocus & KeyboardFocus)
- mOwnedFoci = inFocus;
- else
- // otherwise, say no thanks
- ReturnValue = E_FAIL;
- }
- // a TakeNext or a TakePrev on a control which doesn't embed and has the focus should fail
- else if (inCommand == TakeNextCommand || inCommand == TakePrevCommand)
- {
- ReturnValue = E_FAIL;
- }
- // we're being asked/told to release our foci - always comply
- else // if (Spec == ReleaseRequest || Spec == ReleaseCommand)
- {
- if (inFocus & mOwnedFoci != inFocus)
- DebugStr("\pWhat are they doing asking to release foci we don't have?");
-
- mOwnedFoci = FocusSet(mOwnedFoci & ~inFocus); // really easy for us
- }
-
- mContainerSiteP->AcquireContext(mActiveContext->GetContextID(), &Context);
-
- if (!(InOwnedFoci & KeyboardFocus) && (mOwnedFoci & KeyboardFocus))
- {
- // Acquired keyboard focus
- if(mSelectedCell.h != -1 && mSelectedCell.v != -1)
- {
- ::LSetSelect(true, mSelectedCell, mListH); // select cell
- mSelectedCell.h = -1;
- mSelectedCell.v = -1;
- }
- }
- else if ((InOwnedFoci & KeyboardFocus) && !(mOwnedFoci & KeyboardFocus))
- {
- // Lost keyboard focus
- Point Cell = {0, 0};
-
- if ( ::LGetSelect(true, &Cell, mListH) )
- {
- mSelectedCell = Cell;
- ::LSetSelect(false, Cell, mListH); // deselect cell
- }
- }
-
- mContainerSiteP->ReleaseContext(&Context);
-
- // Invalidate the position rectangle so we'll get redrawn
- // if the focus state of the keyboard changed
- if ((InOwnedFoci & KeyboardFocus) != (mOwnedFoci & KeyboardFocus))
- {
- InvalAllContexts();
- }
-
- return ReturnValue;
- }
-
-
- #pragma mark === CListBoxControl::IPersistPropertyBag ===
-
- //
- // CListBoxControl::IPersistPropertyBag::Load
- //
-
- STDMETHODIMP
- CListBoxControl::Load(IPropertyBag* PropertyBag, IErrorLog* pErrorLog)
- {
- ErrorCode ErrCode = E_FAIL;
-
- LoadTextState(PropertyBag, pErrorLog);
-
- ErrCode = OpenStream(mContainerSiteP, (char*)mDataURL, FALSE);
-
- return ErrCode;
- }
-
-
- //=--------------------------------------------------------------------------=
- // CListBoxControl::LoadTextState
- //=--------------------------------------------------------------------------=
- // load in our text state for this control.
- //
- // Parameters:
- // IPropertyBag * - [in] property bag to read from
- // IErrorLog * - [in] errorlog object to use with proeprty bag
- //
- // Output:
- // ErrorCode
- //
- STDMETHODIMP CListBoxControl::LoadTextState(IPropertyBag *PropertyBag, IErrorLog *pErrorLog)
- {
- VARIANT v;
- Uint32 length;
-
- // VariantInit(&v);
-
- v.vt = VT_BSTR;
- v.bstrVal = NULL;
-
- // try to load in the property. if we can't get it, then leave
- // things at their default.
- //
- PropertyBag->Read("data", &v, pErrorLog);
- if (v.bstrVal)
- {
- length = *((Uint32*) v.bstrVal) ;
- strcpy((Char8*)mDataURL, v.bstrVal + sizeof(Uint32));
- CoTaskMemFree(v.bstrVal);
- // VariantInit(&v);
- }
-
- return S_OK;
- }
-
-
- #pragma mark === CListBoxControl::IBindStatusCallback ===
-
- //
- // CListBoxControl::OnStopBinding
- //
-
-
- STDMETHODIMP
- CListBoxControl::OnStopBinding(ErrorCode Result, const Char8* Error)
- {
- CBaseBindStatusCallback::OnStopBinding(Result, Error);
-
- mLoaded = true;
-
- if (mBindSiteP)
- {
- mBindSiteP->Release();
- mBindSiteP = 0;
- }
-
- return S_OK;
- }
-
-
- //
- // CListBoxControl::OnDataAvailable
- //
-
- STDMETHODIMP
- CListBoxControl::OnDataAvailable(Uint32 BSCF, Uint32 Size, FORMATETC* FormatEtc, STGMEDIUM* StgMedium)
- {
- OSErr Err = noErr;
-
- CBaseBindStatusCallback::OnDataAvailable(BSCF, Size, FormatEtc, StgMedium);
-
- if (StgMedium->tymed == TYMED_ISTREAM)
- {
- if (!mData && Size)
- {
- mData = (listitemdata**)(::NewHandle(0));
- mContainerSiteP->SetIdleTime(DataAvailableIdleTime, DataAvailableIdleRefCon);
- }
-
- if (mData)
- {
- Boolean EndOfFile = Size == 0;
-
- while (EndOfFile || Size--) // order is important here - if EOF is true then we don't want to change dwSize!
- {
- Char8 InChar;
-
- if (EndOfFile)
- {
- InChar = '\r';
- EndOfFile = false;
- }
- else
- StgMedium->pstm->Read(&InChar, 1, NULL);
-
- // if the charater isn't a newline then add it into the buffer
- if (InChar != '\r' && InChar != '\n')
- {
- if (mItemInProgressIndex < 254)
- mItemInProgress.Data[++mItemInProgressIndex] = InChar;
- }
- else if (mItemInProgressIndex > 0)
- // terminate the item in the buffer, add it to the handle
- {
- mItemInProgress.Data[0] = mItemInProgressIndex;
- mItemInProgress.Inserted = false;
- mChanged = true;
- ::SetHandleSize( Handle(mData), sizeof(listitemdata) * (mItemCount + 1));
- ::BlockMove( (Char8*)(&mItemInProgress), (Char8*)((*mData) + mItemCount++), sizeof(listitemdata));
-
- // start putting data at the beginning again
- mItemInProgressIndex = 0;
- }
- }
- }
- }
- if (StgMedium->pUnkForRelease != NULL)
- StgMedium->pUnkForRelease->Release();
-
- return S_OK;
- }
-
-
-