// =========================================================================== // UAMListBox.c © 1997 Microsoft Corp. All rights reserved. // =========================================================================== // List box routines for maintaining a list in a dialog. This unit is required // for the custom volume list dialog. // // =========================================================================== #include #include #include "UAMUtils.h" #include "UAMListBox.h" ListHandle gList; // --------------------------------------------------------------------------- // ¥ UAM_MakeList() // --------------------------------------------------------------------------- // Create a new list in the dialog window. void UAM_MakeList(DialogPtr inDialog, short inItem, short inFont, short inSize, short inProc, Boolean inHasScroll) { Rect theListRect; UAM_DLOG(inDialog).listID = inItem; UAM_DLOG(inDialog).listRect = UAM_GetItemRect(inDialog, inItem); UAM_DLOG(inDialog).listFont = inFont; UAM_DLOG(inDialog).listSize = inSize; UAM_DLOG(inDialog).listHasScrollBar = inHasScroll; UAM_DLOG(inDialog).hasList = true; // //If the list has a scrollbar, leave room for it on the right. // theListRect = UAM_DLOG(inDialog).listRect; if (UAM_DLOG(inDialog).listHasScrollBar) { theListRect.right -= 15; } SetRect(&UAM_DLOG(inDialog).dataBounds, 0, 0, 1, 0); UAM_DLOG(inDialog).cSize.h = theListRect.right - theListRect.left; UAM_DLOG(inDialog).cSize.v = 0; TextFont(UAM_DLOG(inDialog).listFont); TextSize(UAM_DLOG(inDialog).listSize); UAM_DLOG(inDialog).dialogList = LNew( &theListRect, &UAM_DLOG(inDialog).dataBounds, UAM_DLOG(inDialog).cSize, inProc, inDialog, TRUE, FALSE, FALSE, UAM_DLOG(inDialog).listHasScrollBar ); UAM_DLOG(inDialog).cSize.v = -1; if (UAM_DLOG(inDialog).dialogList != NULL) { (**(UAM_DLOG(inDialog).dialogList)).selFlags = lUseSense + lNoExtend; LSetDrawingMode(TRUE, UAM_DLOG(inDialog).dialogList); } } // --------------------------------------------------------------------------- // ¥ UAM_ListUpdate() // --------------------------------------------------------------------------- // Update (redraw) the list box, probably due to an update event. void UAM_ListUpdate(DialogPtr inDialog) { Rect theListRect; TextFont(UAM_DLOG(inDialog).listFont); TextSize(UAM_DLOG(inDialog).listSize); LUpdate(inDialog->visRgn, UAM_DLOG(inDialog).dialogList); theListRect = UAM_DLOG(inDialog).listRect; if (UAM_DLOG(inDialog).listHasScrollBar) { theListRect.right -= 15; } InsetRect(&theListRect, -1, -1); FrameRect(&theListRect); } // --------------------------------------------------------------------------- // ¥ UAM_ListMoveToItem() // --------------------------------------------------------------------------- // Move to the first item of this pressed letter/combo. void UAM_ListMoveToItem(short inCode, unsigned long inLastTime, ListHandle inList) { #pragma unused(inLastTime) Cell theCell = {0,0}; Str32 theKey; Str32 theName; UAMListData theData; short theDataLen; theKey[0] = 1; theKey[1] = (char)inCode; // //We use UpperString() in this routine for strong compatibility across //localized of versions of the UAM. // UpperString(theKey, false); while(theCell.v < (*inList)->dataBounds.bottom) { theDataLen = sizeof(UAMListData); LGetCell((Ptr)&theData, &theDataLen, theCell, inList); UAM_PStrCopy(theData.volumeName, theName); UpperString(theName, false); if ((theName[1] == theKey[1]) && (theData.isActive)) { UAM_SelectOneCell(theCell, inList); LAutoScroll(inList); break; } theCell.v++; } } // --------------------------------------------------------------------------- // ¥ UAM_ListKeyNavigation() // --------------------------------------------------------------------------- // Navigate the list box using the keyboard. void UAM_ListKeyNavigation(short inCode, long inModifiers, ListHandle inList) { Cell theCell = {0,0}; UAMListData theData; short theDataLen; short theRows; switch(inCode) { case UAMKey_Up: if (LGetSelect(true, &theCell, inList)) { if (theCell.v > 0) { theCell.v -= 1; } do { theDataLen = sizeof(UAMListData); LGetCell((Ptr)&theData, &theDataLen, theCell, inList); if (theData.isActive == true) { if (inModifiers & shiftKey) { LSetSelect(true, theCell, inList); } else { UAM_SelectOneCell(theCell, inList); } } else if (theCell.v > 0) { theCell.v -= 1; } else { break; } }while(!theData.isActive); // //Scroll the list to the active cell. // LAutoScroll(inList); } break; case UAMKey_Down: if (UAM_GetLastSelectedCell(&theCell, inList)) { if (theCell.v < ((*inList)->dataBounds.bottom - 1)) { theCell.v += 1; } do { theDataLen = sizeof(UAMListData); LGetCell((Ptr)&theData, &theDataLen, theCell, inList); if (theData.isActive == true) { if (inModifiers & shiftKey) { LSetSelect(true, theCell, inList); } else { UAM_SelectOneCell(theCell, inList); } } else if (theCell.v < ((*inList)->dataBounds.bottom - 1)) { theCell.v += 1; } else { break; } }while(!theData.isActive); // //Scroll the list to the active cell. // LAutoScroll(inList); } break; case UAMKey_Home: LScroll(-16000, -16000, inList); break; case UAMKey_End: LScroll(16000, 16000, inList); break; case UAMKey_PageUp: case UAMKey_PageDown: theRows = (*inList)->visible.bottom - (*inList)->visible.top - 1; if (inCode == UAMKey_PageUp) { theRows = -theRows; } LScroll(0, theRows, inList); break; default: break; } } // --------------------------------------------------------------------------- // ¥ UAM_SelectOneCell() // --------------------------------------------------------------------------- // Select just one cell in the list. void UAM_SelectOneCell(Cell inCell, ListHandle inList) { Cell theCurrCell = {0,0}; while(LGetSelect(true, &theCurrCell, inList)) { if (*(long *)&theCurrCell == *(long *)&inCell) { LNextCell(true, true, &theCurrCell, inList); } else { LSetSelect(false, theCurrCell, inList); } } LSetSelect(true, inCell, inList); } // --------------------------------------------------------------------------- // ¥ UAM_GetLastSelectedCell() // --------------------------------------------------------------------------- // Get the last selected cell in the list. Boolean UAM_GetLastSelectedCell(Cell *outCell, ListHandle inList) { Cell tCurrCell = {0,0}; Boolean tHasSelection = LGetSelect(true, &tCurrCell, inList); if (tHasSelection) { do { *outCell = tCurrCell; }while(LNextCell(true, true, &tCurrCell, inList) && LGetSelect(true, &tCurrCell, inList)); } return(tHasSelection); } // --------------------------------------------------------------------------- // ¥ UAM_SortSwapProc() // --------------------------------------------------------------------------- // Sorting swap routine. void UAM_SortSwapProc(size_t inOne, size_t inTwo) { Cell theCell1, theCell2; UAMListData theData1, theData2; short theDataLen1 = sizeof(UAMListData); short theDataLen2 = sizeof(UAMListData); theCell1.h = 0; theCell1.v = inOne; theCell2.h = 0; theCell2.v = inTwo; LGetCell((Ptr)&theData1, &theDataLen1, theCell1, gList); LGetCell((Ptr)&theData2, &theDataLen2, theCell2, gList); if ((theDataLen1 != 0) && (theDataLen2 != 0)) { LSetCell((Ptr)&theData2, theDataLen2, theCell1, gList); LSetCell((Ptr)&theData1, theDataLen1, theCell2, gList); } } // --------------------------------------------------------------------------- // ¥ UAM_SortCompProc() // --------------------------------------------------------------------------- // Sorting compare routine. We need a custom compare routine since we only // want to compare the volume names, not the other data in the struct. int UAM_SortCompProc(size_t inOne, size_t inTwo) { Cell theCell1, theCell2; UAMListData theData1, theData2; short theDataLen = sizeof(UAMListData); theCell1.h = 0; theCell1.v = inOne; theCell2.h = 0; theCell2.v = inTwo; LGetCell((Ptr)&theData1, &theDataLen, theCell1, gList); LGetCell((Ptr)&theData2, &theDataLen, theCell2, gList); return(CompareString(theData1.volumeName,theData2.volumeName, NULL)); } // --------------------------------------------------------------------------- // ¥ UAM_SortList() // --------------------------------------------------------------------------- // Sorts the volume list in alphabetical order. void UAM_SortList(DialogPtr inDialog) { gList = UAM_DLOG(inDialog).dialogList; /* _qsort( (*UAM_DLOG(inDialog).dialogList)->dataBounds.bottom, (__cmp1_func)UAM_SortCompProc, (__swap1_func)UAM_SortSwapProc ); */ } // --------------------------------------------------------------------------- // ¥ UAM_AddListData() // --------------------------------------------------------------------------- // Add data to the list by adding a new row and inserting the data ptr into // the list's data field. void UAM_AddListData(DialogPtr inDialog, Ptr inData, short inDataSize) { UAM_DLOG(inDialog).cSize.h = 0; UAM_DLOG(inDialog).cSize.v = LAddRow(1, 32767, UAM_DLOG(inDialog).dialogList); LSetCell(inData, inDataSize, UAM_DLOG(inDialog).cSize, UAM_DLOG(inDialog).dialogList); LDraw(UAM_DLOG(inDialog).cSize, UAM_DLOG(inDialog).dialogList); } // --------------------------------------------------------------------------- // ¥ UAM_GetListData() // --------------------------------------------------------------------------- // Get the data associated with a cell in the list box. Ptr UAM_GetListData(DialogPtr inDialog, Cell inCell, short *inDataSize) { Ptr theData = NULL; theData = NewPtrClear(*inDataSize); if (theData != NULL) { // //Get the data from the cell data handle. // LGetCell(theData, inDataSize, inCell, UAM_DLOG(inDialog).dialogList); // //Now set our new pointer size to the actual size of the data returned. // SetPtrSize(theData, *inDataSize); } return(theData); } // --------------------------------------------------------------------------- // ¥ UAM_CalculateBoxRect() // --------------------------------------------------------------------------- // Calculate the rectangle for the check box that lives in this cell. The // defines below much match those in the UAM LDEF. #define kBoxWidth 11 #define kBoxHeight 11 void UAM_CalculateBoxRect(Rect *inRect) { SetRect( inRect, inRect->right - (kBoxWidth + 5), inRect->top + 3, inRect->right - 5, inRect->top + 3 + kBoxWidth ); } // --------------------------------------------------------------------------- // ¥ UAM_GetCellCheckBox() // --------------------------------------------------------------------------- // Return the rect of the checkbox for a given cell. void UAM_GetCellCheckBox(DialogPtr inDialog, Cell inCell, Rect *outRect) { LRect(outRect, inCell, UAM_DLOG(inDialog).dialogList); UAM_CalculateBoxRect(outRect); } // --------------------------------------------------------------------------- // ¥ UAM_CheckBoxClick() // --------------------------------------------------------------------------- // Check for a user click inside a checkbox in our list box. void UAM_CheckBoxClick(DialogPtr inDialog, Point inMouseLoc) { Rect theCellRect; Cell theCell; short theDataOffset; short theDataLen; UAMListDataP theData; ListHandle theListH = UAM_DLOG(inDialog).dialogList; Point theClickLoc = (*theListH)->clikLoc; Point theRealLoc = (*theListH)->mouseLoc; // //Obtain the rectangle of the cell that was just clicked in //and get the rect of the checkbox. // theCell = UAM_GetLastListClick(inDialog); UAM_GetCellCheckBox(inDialog, theCell, &theCellRect); // //Now determine if the click was actually in the checkbox or in another //part of the cell that we don't care about. // if ( (PtInRect(theClickLoc, &theCellRect)) && (PtInRect(inMouseLoc, &theCellRect)) && (PtInRect(theRealLoc, &theCellRect)) ) { // //The mouse click was in the checkbox of one of our cells, so //now we need to get the data associated with that cell. // LGetCellDataLocation(&theDataOffset, &theDataLen, theCell, theListH); // //If we get data, then determine what the current state of the checkbox //should be and then invalidate the checkbox rect to force a redraw. // if ((theDataOffset != -1) && (theDataLen != -1)) { theData = (UAMListDataP)((*(*theListH)->cells) + theDataOffset); theData->isChecked = (theData->isChecked) ? FALSE : TRUE; InvalRect(&theCellRect); } // //We don't want double clicks in the checkbox to count //as a 'real' double click. // UAM_DLOG(inDialog).doubleClick = false; } } // --------------------------------------------------------------------------- // ¥ UAM_ListDialogFilter() // --------------------------------------------------------------------------- // This is called by UAM_DialogFilter(), it processes user action to our // dialog list box. Boolean UAM_ListDialogFilter(DialogPtr inDialog, EventRecord *event, short *itemHit) { Point theMouseLoc; Boolean theResult = false; Cell theCell = {0,0}; theMouseLoc = event->where; GlobalToLocal(&theMouseLoc); if (PtInRect(theMouseLoc, &UAM_DLOG(inDialog).listRect)) { // //You must always set the proper font and size! // TextFont(UAM_DLOG(inDialog).listFont); TextSize(UAM_DLOG(inDialog).listSize); // //Have the ListManager handle the nitty gritty of user action and //save the cell that the user actually clicked in. // UAM_DLOG(inDialog).doubleClick = LClick(theMouseLoc, event->modifiers, UAM_DLOG(inDialog).dialogList); theCell = LLastClick(UAM_DLOG(inDialog).dialogList); UAM_DLOG(inDialog).lastCell.h = theCell.h; UAM_DLOG(inDialog).lastCell.v = theCell.v; // //Call the click routine to handle clicks in the checkboxes. // UAM_CheckBoxClick(inDialog, theMouseLoc); // //Signal that the list box was indeed the item the user hit. // *itemHit = UAM_DLOG(inDialog).listID; theResult = true; } return(theResult); } // --------------------------------------------------------------------------- // ¥ UAM_ListGotDoubleClick() // --------------------------------------------------------------------------- // Returns TRUE if the user doubled clicked in the list box. Boolean UAM_ListGotDoubleClick(DialogPtr inDialog) { return(UAM_DLOG(inDialog).doubleClick); } // --------------------------------------------------------------------------- // ¥ UAM_GetLastListClick() // --------------------------------------------------------------------------- // Returns the cell that the user last clicked in. Cell UAM_GetLastListClick(DialogPtr inDialog) { return(UAM_DLOG(inDialog).lastCell); }