2025-04-27 07:49:33 -04:00

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);
}