1 line
15 KiB
C
1 line
15 KiB
C
// ===========================================================================
|
|
// 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 <Lists.h>
|
|
#include <stdlib.h>
|
|
|
|
#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);
|
|
}
|