/*===============================
Copyright © 1998-2002 Brian Hall

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*===============================*/
#include "BlugsPrivate.h"

#pragma mark ¥¥¥Module Data¥¥¥
static void		local_BLInitTitles( UInt16 inCount, UInt16 inTitle,
									BLTitleBarRef inBar, BlugsRef inList );
static void		local_BLDeinitTitles( UInt16 inCount, UInt16 inTitle, BLTitleBarRef inBar, BlugsRef inList );
static Boolean	local_BLSelectTitle( UInt16 inTitle, BLTitleBarHdl inBar, BlugsRef inList );
static Boolean	local_BLSendClickToTitleHandler( UInt16 inTitle, const Rect* inTitleRect,
												Point inWhereLocal, EventModifiers inModifiers,
												BLTitleBarHdl inBar, BlugsRef inList );
static Boolean	local_BLTrackTitleClick( UInt16 inTitle, const Rect* inTitleRect,
										Point inWhere, EventModifiers inModifiers, UInt32 inWhen,
										UInt16* outNewSelection, BLTitleBarRef inBar, BlugsRef inList );
static void		local_BLTempAddFlagTitle( Boolean inDraw, UInt8 inFlag, UInt16 inTitle,
											BLTitleBarRef inBar, BlugsRef inList );
static void		local_BLHTitleDragResize( BLTitleZone inZone, Point inWhere, UInt16 inTitle, BlugsRef inList );
static void		local_BLVTitleDragResize( BLTitleZone inZone, Point inWhere, UInt16 inTitle, BlugsRef inList );
static void 	local_BLTitleDragReorder( Point inWhereLocal, EventModifiers inModifiers,
											SInt16 inWhen, UInt16 inTitle, Boolean inVertical,
											BlugsRef inList );
static GWorldPtr local_BLSetTitleDragImage( DragRef inDragRef, UInt16 inTitle,
											const Rect* inTitleRect, Point inOffset,
											BLTitleBarHdl inBar, BlugsRef inList );
static pascal OSErr local_DragTitleInputProc( Point *ioMouse, SInt16 *inModifiers,
											void *inDragInputRefCon, DragRef inDragRef );
static void		local_BLHTitleDragResizeThickness( Point inWhere, BLTitleBarHdl inBar, BlugsRef inList );
static void		local_BLVTitleDragResizeThickness( Point inWhere, BLTitleBarHdl inBar, BlugsRef inList );




#define		blThicknessResizeMin	16	// Try this for testing purposes
#define		blDefaultThickness		16

#pragma mark -
#pragma mark ¥¥¥New and Delete¥¥¥
//===============================
// Top left storage sticks around now: if there already is a title bar in this orientation
//	we wipe it clean and recycle the memory.
BL_PROC OSErr BLNewTitleBar( Boolean inVertical, const BLTitleBarInfo* inInfo, BlugsRef inList )
{
	OSErr		err;
	
	_CheckHandlerFlag(inList)
	err = _BLValidateList( inList );
	if (!err)
	{
		BLTitleBarHdl		theBar;
		BLTitleArrayHdl		arrayH = nil;
		UInt16				nTitles;
		
		if (inVertical)
		{
			theBar = bl_VTitle(inList);
			nTitles = bl_NRows(inList);
		}
		else
		{
			theBar = bl_HTitle(inList);
			nTitles = bl_NCols(inList);
		}
		// If it exists, recycle it.
		if (theBar)
		{
			arrayH = (*theBar)->titles;
			local_BLDeinitTitles( 0, 1, theBar, inList );
		}
		else
		{
			theBar = (BLTitleBarHdl)NewHandle( sizeof(BLTitleBarRec) );
			if (!theBar) err = memFullErr;
			else
			{
				_BLZeroMemory( (Ptr)*theBar, sizeof(BLTitleBarRec) );
				arrayH = (BLTitleArrayHdl)_VANew( nTitles, sizeof(BLTitleRec), true );
				if (!arrayH) err = memFullErr;
				else
				{
					if (inVertical) bl_VTitle(inList) = theBar;
					else bl_HTitle(inList) = theBar;
					(*theBar)->titles = arrayH;
				}
			}
		}
		if (!err)
		{
			UInt16	thickness, flags;
			
			thickness = inInfo->thickness;
			flags = inInfo->titleBarFlags & blAllPublicTitleBarFlags;
			// Under Aqua, list header size is fixed.
			// Thus we can't resize the horizontal bar thickness under Aqua.
			if (bl_Aqua && !inVertical)
			{
				OSStatus	status;
				SInt32		metric;
				
				status = GetThemeMetric( kThemeMetricListHeaderHeight, &metric );
				if (!status)
				{
					if (thickness) thickness = metric;
					bl_Clear(flags,blTitleBarResizableThickness);
				}
			}
			(*theBar)->thickness = thickness;
			(*theBar)->fontStyle.flags = kControlUseFontMask | kControlUseSizeMask;
			(*theBar)->fontStyle.font = 1;
			(*theBar)->fontStyle.size = 9;
			if (inVertical) bl_Set(flags,blTitleBarVertical);
			(*theBar)->flags = flags;
			(*theBar)->defaultContentType = inInfo->defaultContentType;
			(*theBar)->defaultTitleFlags = inInfo->defaultTitleFlags;
			local_BLInitTitles( (inVertical) ? bl_NRows(inList) : bl_NCols(inList), 1, theBar, inList );
			// Allow the scroll bars to be recalculated
			_BLAdjustScrollBarSizesAndLocations( inList );
			_BLRecalc( blRecalcScroll | blRecalcThumb | blRecalcRightPin, 0, inList );
			_BLUpdateWorld( blUpdateBlit | blUpdateCorners, nil, inList );
		}
		else
		{
			if (theBar) DisposeHandle( (Handle)theBar );
			if (arrayH) DisposeHandle( (Handle)arrayH );
		}
	} // If valid list
	return err;
}

//===============================
BL_PROC OSErr BLGetTitleBarInfo( Boolean inVertical, BLTitleBarInfo* outInfo, BlugsRef inList )
{
	OSErr		err;
	
	BlockZero( outInfo, sizeof(BLTitleBarInfo) );
	err = _BLValidateList( inList );
	if (!err)
	{
		BLTitleBarRef	bar;
		
		bar = (inVertical) ? bl_VTitle(inList) : bl_HTitle(inList);
		if (bar)
		{
			outInfo->thickness = (*bar)->thickness;
			outInfo->defaultContentType = (*bar)->defaultContentType;
			outInfo->titleBarFlags = (*bar)->flags;
			outInfo->defaultTitleFlags = (*bar)->defaultTitleFlags;
		}
	}
	return err;
}

//===============================
BL_PROC OSErr BLSetTitleBarInfo( Boolean inVertical, UInt16 inWhichFields,
								const BLTitleBarInfo* inInfo, BlugsRef inList )
{
	OSErr		err;
	
	err = _BLValidateList( inList );
	if (!err)
	{
		BLTitleBarRef	bar;
		UInt16			flags;
		
		flags = inInfo->titleBarFlags;
		bar = (inVertical) ? bl_VTitle(inList) : bl_HTitle(inList);
		if (bar)
		{
			BLRecalcOptions	recalcOptions = 0;
			Boolean			doScrollSizes = false;
			
			if (bl_Test(inWhichFields,blSetTitleBarThickness))
			{
				UInt16	thickness;
					
				thickness = inInfo->thickness;
				if (thickness != (*bar)->thickness)
				{
					if (bl_Aqua && !inVertical)
					{
						OSStatus	status;
						SInt32		metric;
						
						status = GetThemeMetric( kThemeMetricListHeaderHeight, &metric );
						if (!status) if (thickness) thickness = metric;
						bl_Clear(flags,blTitleBarResizableThickness);
						doScrollSizes = true;
					}
					(*bar)->thickness = thickness;
					bl_Set(recalcOptions,blRecalcOffsets | blRecalcVisCells | blRecalcThumb | blRecalcScroll);
					if (inVertical) bl_Set(recalcOptions,blRecalcRightPin);
				}
			}
			if (bl_Test(inWhichFields,blSetTitleBarDefaultContentType))
				(*bar)->defaultContentType = inInfo->defaultContentType;
			if (bl_Test(inWhichFields,blSetTitleBarFlags))
				(*bar)->flags = _BLProcessFlags( inInfo->whichTitleBarFlags & blAllPublicTitleBarFlags,
												flags, (*bar)->flags );
			if (bl_Test(inWhichFields,blSetTitleBarDefaultTitleFlags))
				(*bar)->defaultTitleFlags = _BLProcessFlags( inInfo->whichDefaultTitleFlags & blAllPublicTitleFlags,
															inInfo->defaultTitleFlags,
															(*bar)->defaultTitleFlags );
			_BLAdjustScrollBarSizesAndLocations( inList );
			_BLRecalc( recalcOptions, 1, inList );
			_BLUpdateWorld( blUpdateBlit | blUpdateCorners, nil, inList );
		}
	}
	return err;
}

//===============================
// Danger! This modifies the list so its title bar is nil.
void _BLDisposeTitleBar( BLTitleBarHdl inBar, BlugsRef inList )
{
	BLHandlerParamBlock	pb;
	BLTitleBarHdl		vTitle, hTitle;
	
	_BLDisposeTitles( 0, 1, inBar, inList );
	DisposeHandle( (Handle)(*inBar)->titles );
	vTitle = bl_VTitle(inList);
	hTitle = bl_HTitle(inList);
	// Deinitialize the top left no matter which bar we're disposing
	if (vTitle)
	{
		if ((*vTitle)->topLeftContent)
		{
			_BLCallHandlerForTitle( blCellDeinitMsg, 0, &pb, vTitle, inList );
			(*vTitle)->topLeftContent = 0;
		}
	}
	DisposeHandle( (Handle)inBar );
	if (inBar == hTitle) bl_HTitle(inList) = nil;
	else bl_VTitle(inList) = nil;
}

//===============================
// This is called from column/row insertion/deletion routines also; can't be static
// If count is 0, dispose all
void _BLDisposeTitles( UInt16 inCount, UInt16 inTitle, BLTitleBarHdl inBar, BlugsRef inList )
{
	UInt16		nTitles;
	
	if (bl_BarVert(inBar)) nTitles = bl_NRows(inList);
	else nTitles = bl_NCols(inList);
	if (inCount > nTitles) inCount = nTitles;
	else if (!inCount) inCount = nTitles;
	if (nTitles)
	{
		local_BLDeinitTitles( inCount, inTitle, inBar, inList );
		_VARemove( inCount, inTitle, nTitles, sizeof(BLTitleRec), (Handle)(*inBar)->titles );
	}
}

//===============================
static void local_BLInitTitles( UInt16 inCount, UInt16 inTitle,
								BLTitleBarRef inBar, BlugsRef inList )
{
	BLTitlePtr			titleP;
	UInt16				flags, i;
	BLContentType		defaultContent;
	
	defaultContent = (*inBar)->defaultContentType;
	flags = (*inBar)->defaultTitleFlags;
	for (i = 0; i < inCount; i++)
	{
		titleP = (BLTitlePtr)(bl_NthTitleAddr(inTitle,inBar));
		titleP->flags = flags;
		if (defaultContent) _BLSetTitleContentType( false, inTitle + i, defaultContent, inBar, inList );
	}
}

//===============================
static void local_BLDeinitTitles( UInt16 inCount, UInt16 inTitle, BLTitleBarHdl inBar, BlugsRef inList )
{
	UInt16				nTitles, i;
	BLHandlerParamBlock	pb;
	
	if (bl_BarVert(inBar)) nTitles = bl_NRows(inList);
	else nTitles = bl_NCols(inList);
	if (inCount > nTitles) inCount = nTitles;
	else if (!inCount) inCount = nTitles;
	for (i = 0; i < inCount; i++)
		_BLCallHandlerForTitle( blCellDeinitMsg, inTitle + i, &pb, inBar, inList );
}

//===============================
OSErr _BLAddTitles( UInt16 inCount, UInt16 inAddHere, BLTitleBarHdl inBar, BlugsRef inList )
{
	BLTitleArrayHdl		arrayH;
	UInt16				nTitles;
	OSErr				err = noErr;
	
	if (bl_BarVert(inBar)) nTitles = bl_NRows(inList);
	else nTitles = bl_NCols(inList);
	arrayH = (*inBar)->titles;
	_AssertStr( arrayH != nil, "Internal error: no title array." );
	if (!arrayH) err = memFullErr;
	if (!err) err = _VAAdd( inCount, inAddHere, nTitles, sizeof(BLTitleRec), (Handle)arrayH, true );
	if (!err) local_BLInitTitles( inCount, inAddHere, inBar, inList );
	return err;
}


//===============================
BLContentType _BLGetTitleContentType( UInt16 inTitle, BLTitleBarHdl inBar )
{
	BLContentType	content;
	
	if (!inTitle)
	{
		if (bl_BarVert(inBar)) content = (*inBar)->topLeftContent;
		else content = 0;
	}
	else content = ((BLTitlePtr)(bl_NthTitleAddr(inTitle,inBar)))->contentType;
	return content;
}


//===============================
OSErr _BLMoveTitles( UInt16 inMoveTitle, UInt16 inAfterThisTitle, UInt16 inCount,
					UInt16 inNTitles, BLTitleBarHdl inTitleBar )
{
	OSErr	err;
	
	err = _VAMoveAfter( inCount, inMoveTitle, inAfterThisTitle, sizeof(BLTitleRec),
						inNTitles, (Handle)((*inTitleBar)->titles) );
	return err;
}

#pragma mark -
#pragma mark ¥¥¥Selection¥¥¥
//===============================
BL_PROC OSErr BLSelectTitle( Boolean inVertical, UInt16 inTitle, BlugsRef inList )
{
	OSErr	err;
	
	err = _BLValidateList( inList );
	if (!err)
	{
		BLTitleBarRef	bar;
		
		bar = (inVertical) ? bl_VTitle(inList) : bl_HTitle(inList);
		err = _BLValidateTitle( false, inTitle, bar, inList );
		if (!err)
		{
			Boolean		selectionChanged;
			
			selectionChanged = local_BLSelectTitle( inTitle, bar, inList );
			if (!inVertical && selectionChanged)
			{
				// When we select a title that wasn't selected before,
				//	the best thing to do is to sort in the natural direction:
				//	that is, small to large. We set the list's sort direction to this and
				//	sort without 'advancing' to a new state.
				//bl_Set((*inList)->privateFlags,blSorted);
				//bl_Clear((*inList)->privateFlags,blSortedBigSmall);
				BLGetColumnUID( inTitle, &(*inList)->primarySortColumn, inList );
				_BLSort( blSortStateSorted, inList );
			}
		}
	}
	return err;
}

//===============================
// Pass zero for inTitle to deselect all.
// Because we want to restore normal color for drawing title text when a title goes
//	from being pressed (white text) to selected (black text) we want to update the selected
//	title even if it was selected before.
// Under Aqua, we may need to update more titles than just the old selection because the 'left neighbor
//	selected' state can change for potentially two other titles. At times is is necessary to
//	update the new selection, its right neighbor, the old selection, and its right neighbor.
//	So to make it simple we update the entire title bar.
static Boolean local_BLSelectTitle( UInt16 inTitle, BLTitleBarHdl inBar, BlugsRef inList )
{
	UInt16	oldSelection;
	Boolean	selectionChanged;
	
	oldSelection = (bl_BarVert(inBar)) ? BLGetRowFromUID( &(*inBar)->whichSelected, inList ) :
										BLGetColumnFromUID( &(*inBar)->whichSelected, inList );
	selectionChanged = (oldSelection != inTitle);
	if (selectionChanged)
	{
		if (bl_BarVert(inBar)) BLGetRowUID( inTitle, &(*inBar)->whichSelected, inList );
		else BLGetColumnUID( inTitle, &(*inBar)->whichSelected, inList );
		if (oldSelection && !bl_Aqua) _BLUpdateTitle( oldSelection, inBar, inList );
	}
	if (!bl_Aqua)
	{
		if (inTitle) _BLUpdateTitle( inTitle, inBar, inList );
	}
	else _BLUpdateBarOnly( inBar, inList );
	return selectionChanged;
}

//===============================
BL_PROC UInt16 BLGetSelectedTitle( Boolean inVertical, BlugsRef inList )
{
	OSErr	err;
	UInt16	title = 0;
	
	err = _BLValidateList( inList );
	if (!err)
	{
		BLTitleBarRef	bar;
		
		bar = (inVertical) ? bl_VTitle(inList) : bl_HTitle(inList);
		title = (inVertical) ? BLGetRowFromUID( &(*bar)->whichSelected, inList ) :
								BLGetColumnFromUID( &(*bar)->whichSelected, inList );
	}
	return title;
}

//===============================
// Returns true if a new title was selected, so we can track need to resort a column.
// Also returns the new selection (if there is one) so the sort column can be updated.
Boolean _BLHTitleBarClick( BLHitTestPtr inHitTest, Point inWhere,
							EventModifiers inModifiers, UInt32 inWhen,
							UInt16* outNewSelection, BlugsRef inList )
{
	BLTitleBarHdl	theBar;
	BLTitleZone		zone;
	UInt16			nthTitle;
	Boolean			newSelection = false;
	
	theBar = bl_HTitle(inList);
	_AssertStr( theBar, "Internal error: horizontal title bar does not exist." );
	nthTitle = inHitTest->cell.col;
	zone = inHitTest->u.zone;
	// We can do thickness resizing even if we're not in a title
	if (zone == blZoneBottom) local_BLHTitleDragResizeThickness( inWhere, theBar, inList );
	else
	{
		// Are we resizing?
		if (zone == blZoneRight || zone == blZoneLeft)
		{
			// 10/13/2001 Moses -->1.1
			// If there are no columns it's all filler.
			// Can't do anything other than resize thickness, above.
			if (bl_NCols(inList))
			{
				if (inHitTest->part == blHTitleBarFillerPart) nthTitle = 0;
				local_BLHTitleDragResize( zone, inWhere, nthTitle, inList );
			}
		}
		else
		{
			if (inHitTest->part != blHTitleBarFillerPart)
			{
				Rect			titleRect;
				Boolean			handled;
				
				titleRect = inHitTest->rect;
				handled = local_BLSendClickToTitleHandler( nthTitle, &titleRect, inWhere,
															inModifiers, theBar, inList );
				if (!handled) newSelection = local_BLTrackTitleClick( nthTitle, &titleRect, inWhere,
																	inModifiers, inWhen, outNewSelection,
																	theBar, inList );
			}
		}
	}
	return newSelection;
}

//===============================
void _BLVTitleBarClick( BLHitTestPtr inHitTest, Point inWhere, EventModifiers inModifiers,
						UInt32 inWhen, BlugsRef inList )
{
	BLTitleBarHdl	theBar;
	BLTitleZone		zone;
	UInt16			barFlags, nthTitle;
	
	theBar = bl_VTitle(inList);
	_AssertStr( theBar, "Internal error: vertical title bar does not exist." );
	nthTitle = inHitTest->cell.row;
	zone = inHitTest->u.zone;
	barFlags = (*theBar)->flags;
	// We can do thickness resizing even if we're not in a title
	if (zone == blZoneRight) local_BLVTitleDragResizeThickness( inWhere, theBar, inList );
	else
	{
		if (zone == blZoneTop || zone == blZoneBottom)
		{
			// 10/13/2001 Moses -->1.1
			// If there are no columns it's all filler.
			// Cant do anything other than resize thickness, above.
			if (bl_NRows(inList))
			{
				if (inHitTest->part == blVTitleBarFillerPart) nthTitle = 0;
				local_BLVTitleDragResize( zone, inWhere, nthTitle, inList );
			}
		}
		else
		{
			// Otherwise we are title content area.
			// No other actions possible if not in title.
			if (inHitTest->part != blVTitleBarFillerPart)
			{
				Rect			titleRect;
				Boolean			handled;
				
				titleRect = inHitTest->rect;
				handled = local_BLSendClickToTitleHandler( nthTitle, &titleRect, inWhere,
															inModifiers, theBar, inList );
				if (!handled) (void)local_BLTrackTitleClick( nthTitle, &titleRect, inWhere,
															inModifiers, inWhen, nil, theBar, inList );
			} // not filler part
		}
	}
}

//===============================
// Returns true if the click was handled.
// If the title wants a click, only send it if the click is in the title's region.
// In that case, simply invoke handler, redraw if necessary, then bail out.
// Since the handler takes over, we never return true since the title isn't selected. 
static Boolean local_BLSendClickToTitleHandler( UInt16 inTitle, const Rect* inTitleRect,
												Point inWhereLocal, EventModifiers inModifiers,
												BLTitleBarHdl inBar, BlugsRef inList )
{
	Boolean			handled = false;
	BLContentType	content;
	OSErr			err;
	UInt32			features;
	
	content = _BLGetTitleContentType( inTitle, inBar );
	err = _BLGetHandlerFeatures( inContent, &features );
	if (!err)
	{
		if (bl_Test(features,blWantsClick))
		{
			BLHandlerParamBlock	pb;
			UInt32				response;
			RgnHandle			contentRgn = NewRgn();
			
			pb.inRect = *inTitleRect;
			if (bl_Test(features,blWantsRegion))
			{
				pb.inRegion = contentRgn;
				response = _BLCallHandlerForTitle( blCellRegionMsg, inTitle, &pb, inBar, inList );
			}
			else RectRgn( contentRgn, inTitleRect );
			// If the click is in the modified region, give it to handler.
			if (PtInRgn( inWhereLocal,contentRgn ))
			{
				RgnHandle	saveClip;
				Rect		titleBarRect;
				
				pb.inEventModifiers = inModifiers;
				pb.inEventWhereLocal = inWhereLocal;
				// We don't want the drawing overlapping into the corner.
				titleBarRect = _BLTitleBarRect( inBar, inList );
				saveClip = _BLClipToRectIntersection( inTitleRect, &titleBarRect );
				response = _BLCallHandlerForTitle( blCellClickMsg, inTitle, &pb, inBar, inList );
				if (saveClip)
				{
					SetClip( saveClip );
					DisposeRgn( saveClip );
				}
				if (bl_Test(response,blCellClickUpdate)) _BLUpdateTitle( inTitle, inBar, inList );
				// We still need to dispose of regions to avoid mem leak, don't return yet.
				handled = bl_Test(response,blCellClickHandled);
			}
			DisposeRgn( contentRgn );
		}
	}
	return handled;
}

//===============================
// Returns true if there was a new selection. outNewSelection can be nil.
// Under Aqua, returns true if the click was in the old selection.
static Boolean local_BLTrackTitleClick( UInt16 inTitle, const Rect* inTitleRect,
										Point inWhere, EventModifiers inModifiers, UInt32 inWhen,
										UInt16* outNewSelection, BLTitleBarHdl inBar, BlugsRef inList )
{
	Boolean					canDoDrag, canSelect, vertical, newSelection = false, keepGoing;
	SInt16					originalMousePosition, mousePosition;
	Point					mouse;
	UInt16					barFlags, selectedTitle;
	
	barFlags = (*inBar)->flags;
	// Test for drag manager and drag-to-reorder flag.
	canDoDrag = (bl_DragManager && bl_Test(barFlags,blTitleBarReorderable));
	mouse = inWhere;
	vertical = bl_BarVert(inBar);
	if (vertical)
	{
		originalMousePosition = mouse.v;
		if (bl_Disclosure(inList)) canDoDrag = false;
	}
	else originalMousePosition = mouse.h;
	canSelect = bl_Test( ((BLTitlePtr)(bl_NthTitleAddr(inTitle,inBar)))->flags,blTitleSelectable);
	// If we can't drag-to-reorder and the title is already selected, we're done.
	// Under Aqua, we do want to track a click in a selected title in the horizontal title bar.
	selectedTitle = (bl_BarVert(inBar)) ? BLGetRowFromUID( &(*inBar)->whichSelected, inList ) :
										BLGetColumnFromUID( &(*inBar)->whichSelected, inList );
	keepGoing = (canDoDrag || (inTitle != selectedTitle && canSelect));
	if (bl_Aqua) if (inTitle == selectedTitle && !vertical) keepGoing = true;
	if (keepGoing)
	{
		Boolean					didDrag = false;
		Rect					titleBarRect, titleVisibleRect;
		MouseTrackingResult		result = kMouseTrackingMousePressed;
		
		titleBarRect = _BLTitleBarRect( inBar, inList );
		SectRect( inTitleRect, &titleBarRect, &titleVisibleRect );
		do
		{
			// Track mouse position
			if (canSelect && !didDrag)
			{
				if (!PtInRect( mouse, &titleVisibleRect ))
					 _BLTempRemoveFlagTitle( true, blTitleTempSelected, inTitle, inBar, inList );
				else local_BLTempAddFlagTitle( true, blTitleTempSelected, inTitle, inBar, inList );
			}
			_BLTrackMouseLocation( &mouse, &result );
			if (canDoDrag)
			{
				if (vertical) mousePosition = mouse.v;
				else mousePosition = mouse.h;
				if (bl_Abs(originalMousePosition - mousePosition) > blReorderMovementPixelThreshold )
				{
					// TempDeselect it, if it was selected.
					//if (canSelect) _BLTempRemoveFlagTitle( blTitleTempSelected, inTitle, inBar, inList );
					// And drag the column to reorder it.
					local_BLTitleDragReorder( inWhere, inModifiers, inWhen, inTitle, vertical, inList );
					result = kMouseTrackingMouseReleased;
					didDrag = true;
				}
			}
			
		} while (result != kMouseTrackingMouseReleased);
		if (canSelect && !didDrag)
		{
			if (PtInRect(mouse,&titleVisibleRect))
			{
				if (local_BLSelectTitle( inTitle, inBar, inList )) newSelection = true;
				if (bl_Aqua) newSelection = true;
				if (newSelection) if (outNewSelection) *outNewSelection = inTitle;
			}
			_BLTempRemoveFlagTitle( true, blTitleTempSelected, inTitle, inBar, inList );
		}
	}
	return newSelection;
}

//===============================
void _BLTempRemoveFlagTitle( Boolean inDraw, UInt8 inFlag, UInt16 inTitle,
								BLTitleBarHdl inBar, BlugsRef inList )
{
	if (inTitle)
	{
		BLTitlePtr	title;
		
		title = bl_NthTitleAddr(inTitle,inBar);
		if (bl_Test(title->flags,inFlag))
		{
			bl_Clear(title->flags,inFlag);
			if (inDraw) _BLUpdateTitle( inTitle, inBar, inList );
		}
	}
}

//===============================
static void local_BLTempAddFlagTitle( Boolean inDraw, UInt8 inFlag, UInt16 inTitle,
										BLTitleBarHdl inBar, BlugsRef inList )
{
	if (inTitle)
	{
		BLTitlePtr	title;
		
		title = bl_NthTitleAddr(inTitle,inBar);
		if (!bl_Test(title->flags,inFlag))
		{
			bl_Set(title->flags,inFlag);
			if (inDraw) _BLUpdateTitle( inTitle, inBar, inList );
		}
	}
}

//===============================
static void local_BLHTitleDragResize( BLTitleZone inZone, Point inWhere, UInt16 inTitle, BlugsRef inList )
{
	UInt16					resizeTitle, viewWd, min;
	SInt16					origWd;
	Rect					tbRect;
	MouseTrackingResult		result = kMouseTrackingMousePressed;
	
	tbRect = _BLTitleBarRect( bl_HTitle(inList), inList );
	// If inTitle is zero, we are resizing based on a click in the filler title
	if (!inTitle) resizeTitle = bl_NCols(inList);
	else
	{
		// If cursor is to the far right of the title, this one is the title to be resized
		if (inZone == blZoneRight) resizeTitle = inTitle;
		// Otherwise we resize the title to the left of the one we've clicked in
		else resizeTitle = inTitle - 1;
	}
	origWd = _BLGetColumnWidth( resizeTitle, inList );
	viewWd = _BLViewWidth( inList );
	min = _BLGetColMinimumWidth( resizeTitle, inList );
	// Drag the column width around as the user drags
	while (result != kMouseTrackingMouseReleased)
	{
		SInt16		wd, dx;
		Point		currMouse;
	
		dx = 0;
		_BLTrackMouseLocation( &currMouse, &result );
		// Keep resizing only if between title bar top and bottom
		if (currMouse.v >= tbRect.top && currMouse.v <= tbRect.bottom)
		{
			if (currMouse.h < tbRect.left) dx = -(tbRect.left - currMouse.h);
			else if (currMouse.h > tbRect.right) dx = currMouse.h - tbRect.right;
			if (dx)
			{
				SInt32	actualDX;
				
				_BLScroll( blScrollAdjustThumb, dx, 0, &actualDX, nil, inList );
				inWhere.h -= actualDX;
				currMouse.h -= actualDX;
			}
			wd = origWd + currMouse.h - inWhere.h;
			if (wd < min) wd = min;
			BLSetColumnWidth( resizeTitle, wd, inList );
		}
	}
}

//===============================
static void local_BLVTitleDragResize( BLTitleZone inZone, Point inWhere, UInt16 inTitle, BlugsRef inList )
{
	UInt16					resizeTitle = 0, min;
	SInt16					origHt;
	Rect					tbRect;
	MouseTrackingResult		result = kMouseTrackingMousePressed;
	
	tbRect = _BLTitleBarRect( bl_VTitle(inList), inList );
	if (!inTitle) resizeTitle = bl_NRows(inList);
	// If cursor is to the top of the title, the first disclosed one above that is
	//	the title to be resized.	
	else if (inZone == blZoneTop)
	{
		// If disclosure, find the first title (i.e. row) with a nonzero visible height.
		if (bl_Disclosure(inList))
		{
			UInt16		row;
			
			for (row = inTitle - 1; row >= 1; row--)
			{
				if (_BLGetRowVisibleHeight( row, inList ) > 0)
				{
					resizeTitle = row;
					break;
				}
			}
			// Huh? Bail out!!
			_AssertStr( resizeTitle, "Internal error: why are we here? Isn't row #1 disclosed?" );
			if (!resizeTitle) return;
		}
		// If no disclosure, we know that the previous title is visible.
		else resizeTitle = inTitle - 1;
	} // zone top
	// Otherwise we resize the title we've clicked in
	else resizeTitle = inTitle;
	origHt = _BLGetRowVisibleHeight( resizeTitle, inList );
	min = _BLGetRowMinimumHeight( resizeTitle, inList );
	// Drag the row height around as the user drags
	while (result != kMouseTrackingMouseReleased)
	{
		SInt16		ht, dy;
		Point		currMouse;
		
		dy = 0;
		_BLTrackMouseLocation( &currMouse, &result );
		if (currMouse.h >= tbRect.left && currMouse.h <= tbRect.right)
		{
			if (currMouse.v < tbRect.top) dy = -(tbRect.top - currMouse.v);
			else if (currMouse.v > tbRect.bottom) dy = currMouse.v - tbRect.bottom;
			if (dy)
			{
				SInt32	actualDY;
				
				_BLScroll( blScrollAdjustThumb, 0, dy, nil, &actualDY, inList );
				inWhere.v -= actualDY;
				currMouse.v -= actualDY;
			}
			ht = origHt + currMouse.v - inWhere.v;
			if (ht < min) ht = min;
			BLSetRowHeight( resizeTitle, ht, inList );
		}
	}
}

//===============================
// Filter out disclosure lists before calling this routine. If you don't you'll be sorry.
static void local_BLTitleDragReorder( Point inWhereLocal, EventModifiers inModifiers,
										SInt16 inWhen, UInt16 inTitle, Boolean inVertical,
										BlugsRef inList )
{
	DragRef		theDrag;
	OSErr		err;
	
	// Create a drag object
	err = NewDrag( &theDrag );
	if (!err)
	{
		Boolean		draggingTitleData;
		
		// Put in the fact that whether we are dragging a vertical or horizontal title.
		// Also check here to disallow dragging vertical title in disclosure list.
		if ( inVertical ) draggingTitleData = 0;
		else draggingTitleData = 1;
		err = AddDragItemFlavor( theDrag, blPrivateDragItemRef, blDragFlavor_DraggingTitle,
								&draggingTitleData, sizeof(draggingTitleData), flavorSenderOnly );
		if ( err == noErr )
		{
			// Add a flavor to hold the current position of the titleNum column.
			// Initially, it's at its original place, naturally.
			err = AddDragItemFlavor( theDrag, blPrivateDragItemRef, blDragFlavor_CurrentTitlePosition,
									&inTitle, sizeof(inTitle), flavorSenderOnly );
			// We need to know what list we're coming from.
			if ( err == noErr )
			{
				err = AddDragItemFlavor( theDrag, blPrivateDragItemRef, blDragFlavor_OriginList,
										&inList, sizeof(inList), flavorSenderOnly );
				// We also need to know the original scroll position.
				if ( err == noErr )
				{
					BLPixelOffset				originalScrollPos;
					
					if ( inVertical ) originalScrollPos = bl_VScrollLoc(inList);
					else originalScrollPos = bl_HScrollLoc(inList);
					err = AddDragItemFlavor( theDrag, blPrivateDragItemRef, blDragFlavor_Offset,
										&originalScrollPos, sizeof(originalScrollPos), flavorSenderOnly );
					if ( err == noErr )
					{
						Rect				titleRect, viewRect = _BLViewRect( inList );
						BLTitleBarHdl		theBar;
						
						// Set the rectangle of the item to drag.
						if ( inVertical )
						{
							theBar = bl_VTitle(inList);
							(void)_BLTitleRect( inTitle, theBar, &titleRect, inList );
							// Could this generate weird intermediate results, with totalHt & scrollLoc being 32-bit?
							titleRect.right = viewRect.left + bl_TotalWd(inList) - bl_HScrollLoc(inList);
							if ( viewRect.right < titleRect.right ) titleRect.right = viewRect.right;
						}
						else
						{
							theBar = bl_HTitle(inList);
							(void)_BLTitleRect( inTitle, theBar, &titleRect, inList );
							// Could this generate weird intermediate results, with totalHt & scrollLoc being 32-bit?
							titleRect.bottom = viewRect.top + bl_TotalHt(inList) - bl_VScrollLoc(inList);
							if ( viewRect.bottom < titleRect.bottom ) titleRect.bottom = viewRect.bottom;
						}
						err = SetDragItemBounds( theDrag, blPrivateDragItemRef, &titleRect );
						if ( err == noErr )
						{
							Point			offset;
							
							// Add the original mouse offset within the titleRect so we can force the drag into
							// the list rect better.
							offset.h = inWhereLocal.h - titleRect.left;
							offset.v = inWhereLocal.v - titleRect.top;
							err = AddDragItemFlavor( theDrag, blPrivateDragItemRef, blDragFlavor_OriginalMouseOffset, &offset,
													sizeof(offset), flavorSenderOnly );
							if ( err == noErr )
							{
								RgnHandle		tempRgn = NewRgn(), dragRgn = NewRgn();
								DragInputUPP	inputUPP = nil;
								GWorldPtr		dragGWorld = nil;
								
								// Get an offset from local to global coordinates.
								offset.h = offset.v = 0;
								LocalToGlobal( &offset );
								if (bl_TranslucentDrags)
									dragGWorld = local_BLSetTitleDragImage( theDrag, inTitle,
																			&titleRect, offset,
																			theBar, inList );
								// Set the region of the item to drag - outline the entire row/column.
								RectRgn( dragRgn, &titleRect );
								// Hollow out the drag region.
								InsetRect( &titleRect, 2, 2 );
								_BLRgnMinusRect( dragRgn, &titleRect );
								// Convert the drag region to global coordinates.
								OffsetRgn( dragRgn, offset.h, offset.v );
								inputUPP = NewDragInputUPP( local_DragTitleInputProc );
							 	err = SetDragInputProc( theDrag, inputUPP, (void *)inList );
								if ( err == noErr )
								{
									EventRecord		theEvent;
									
									// Fabricate an EventRecord.
									theEvent.what = mouseDown;
									theEvent.message = 0;
									theEvent.when = inWhen;
									theEvent.where = inWhereLocal;
									LocalToGlobal( &theEvent.where );
									theEvent.modifiers = inModifiers;
									if (bl_AllegroAppearance) SetThemeCursor( kThemeClosedHandCursor );
									if ( bl_TranslucentDrags )
									{
										local_BLTempAddFlagTitle( true, blTitleBeingDragged, inTitle, theBar, inList );
										//local_BLTempAddFlagTitle( false, blTitleBeingDragged, inTitle, theBar, inList );
										_BLUpdateTitle( inTitle, theBar, inList );
										_BLUpdateView( blUpdateBlit, inList );
									}
									// Track the drag using the drag manager.
									err = TrackDrag( theDrag, &theEvent, dragRgn );
									if ( bl_TranslucentDrags )
									{
										// Remove the drag hiliting and redraw.
										_BLTempRemoveFlagTitle( true, blTitleBeingDragged, inTitle, theBar, inList );
										//_BLTempRemoveFlagTitle( false, blTitleBeingDragged, inTitle, theBar, inList );
										_BLUpdateWorld( blUpdateBlit, nil, inList );
									}
									InitCursor();
								}
								//if ( inputUPP != nil ) DisposeRoutineDescriptor( inputUPP );
								if ( inputUPP != nil ) DisposeDragInputUPP( inputUPP );
								if ( dragRgn != nil ) DisposeRgn( dragRgn );
								if (dragGWorld) DisposeGWorld( dragGWorld );
							} // No error calling SetDragInputProc.
						} // No error adding blDragFlavor_OriginalMouseOffset data.
					} // No error calling SetDragItemBounds.
				} // No error adding blDragFlavor_Offset data.
			} // No error adding blDragFlavor_CurrentTitlePosition data.
		} // No error adding blDragFlavor_DraggingTitle data.
		DisposeDrag( theDrag );
	} // No error creating drag.
}

//===============================
static GWorldPtr local_BLSetTitleDragImage( DragRef inDragRef, UInt16 inTitle,
											const Rect* inTitleRect, Point inOffset,
											BLTitleBarHdl inBar, BlugsRef inList )
{
	GWorldPtr		saveWorld, dragGWorld;
	GDHandle		saveDevice;
	OSErr			err;
	
	GetGWorld( &saveWorld, &saveDevice );
	// Create an offscreen GWorld holding the title bar.
	err = NewGWorld( &dragGWorld, (bl_Aqua) ? 16 : 8, inTitleRect, nil, saveDevice,
					noNewDevice + useTempMem );
	if (!err)
	{
		PixMapHandle	pm;
		
		// Draw title in the offscreen.
		SetGWorld( dragGWorld, saveDevice );
		pm = GetGWorldPixMap( dragGWorld );
		if (LockPixels( pm ))
		{
			_BLDrawIntersectingCells( inTitleRect, inList );
			// Reset the clip to the entire GWorld.
			ClipRect( inTitleRect );
			_BLDrawTitle( inTitle, inBar, inList );
			//UnlockPixels( pm );
		}
		SetGWorld( saveWorld, saveDevice );
		SetDragImage( inDragRef, pm, nil, inOffset, kDragRegionAndImage + kDragDarkerTranslucency );
	}
	return dragGWorld;
}

//===============================
// Only use this inputProc when dragging titles (horizontal or vertical).
// This input proc makes sure that the title can never be dragged outside the current window.
//
// BLTrackDrag makes sure that the title can never be dragged to another list by checking the
// blDragFlavor_OriginList flavor data and pinning the mouse within the originating list.
// BLTrackDrag also handles constraining to horizontal or vertical movement.
//
// Note: NEVER draw anything within a drag input proc. You WILL get bad looking results.
static pascal OSErr local_DragTitleInputProc( Point *ioMouse, SInt16 *inModifiers,
											void *inDragInputRefCon, DragRef inDragRef )
{
#pragma unused( inModifiers, inDragRef )
	BlugsRef				list = (BlugsRef)inDragInputRefCon;
	Point			offset;
	Rect			box;

	// Find the area that we can drag within.
	GetPortBounds( GetWindowPort( bl_Window(list) ), &box );
	// Need to offset mouse to local coordinates to compare with box.
	offset = *ioMouse;
	GlobalToLocal( &offset );
	if ( !PtInRect( offset, &box ) )
	{
		// If we're outside the window, reset to nearest window border.
		if ( offset.v < box.top ) offset.v = box.top;
		else if ( offset.v > box.bottom ) offset.v = box.bottom;
		if ( offset.h < box.left ) offset.h = box.left;
		else if ( offset.h > box.right ) offset.h = box.right;
		*ioMouse = offset;
		LocalToGlobal( ioMouse );
	}
	return noErr;
}

//===============================
// This is called for the horizontal title bar when the zone is blZoneBottom and thickness
//	resizing is enabled.
static void local_BLHTitleDragResizeThickness( Point inWhere, BLTitleBarHdl inBar, BlugsRef inList )
{
	UInt16					minW, minH;
	SInt16					max, origThickness, lastThickness;
	Rect					tbRect, viewRect;
	ControlRef				vScroll;
	Boolean					recalcVScroll;
	MouseTrackingResult		result = kMouseTrackingMousePressed;
	Point					currMouse = inWhere;
	
	vScroll = bl_VScroll(inList);
	recalcVScroll = (vScroll && bl_SortButton(inList));
	tbRect = _BLTitleBarRect( inBar, inList );
	origThickness = (*inBar)->thickness;
	lastThickness = origThickness;
	viewRect = _BLViewRect( inList );
	_BLMinView( &minW, &minH, inList );
	max = origThickness + bl_Height(viewRect) - minH;
	// Drag the thickness around as the user drags
	while (result != kMouseTrackingMouseReleased)
	{
		SInt16		thickness;
		
		_BLTrackMouseLocation( &currMouse, &result );
		// Keep resizing only if between title bar left and right
		if (currMouse.h >= tbRect.left && currMouse.h <= tbRect.right)
		{
			thickness = origThickness + currMouse.v - inWhere.v;
			if (thickness < blThicknessResizeMin) thickness = blThicknessResizeMin;
			else if (thickness > max) thickness = max;
			if (thickness != lastThickness)
			{
				SInt16		thicknessDelta; // positive if thickness increases
				
				(*inBar)->thickness = thickness;
				thicknessDelta = thickness - lastThickness;
				viewRect.top += thicknessDelta;
				// If there is a sort button, we have to make the top of the vertical scroll
				//	bar even with the new bottom of the horiz title bar
				if (recalcVScroll)
				{
					Rect		controlRect;
					
					controlRect = _BLVScrollRect( inList );
					SetControlBounds( vScroll, &controlRect );
				}
				_BLRecalc( blRecalcVisCells, 0, inList );
				_BLUpdateWorld( blUpdateBlit | blUpdateCorners, nil, inList );
				_BLRecalc( blRecalcVScroll | blRecalcThumb, 0, inList );
				//if (recalcVScroll) Draw1Control( vScroll );
				lastThickness = thickness;
			}
		}
	}
}

//===============================
static void local_BLVTitleDragResizeThickness( Point inWhere, BLTitleBarHdl inBar, BlugsRef inList )
{
	UInt16					minW, minH;
	SInt16					max, origThickness;
	Rect					tbRect, viewRect;
	MouseTrackingResult		result = kMouseTrackingMousePressed;
	Point					currMouse = inWhere;
	
	tbRect = _BLTitleBarRect( inBar, inList );
	origThickness = (*inBar)->thickness;
	viewRect = _BLViewRect( inList );
	_BLMinView( &minW, &minH, inList );
	max = origThickness + bl_Width(viewRect) - minW;
	// Drag the thickness around as the user drags
	while (result != kMouseTrackingMouseReleased)
	{
		SInt16		thickness;
		
		_BLTrackMouseLocation( &currMouse, &result );
		// Keep resizing only if between title bar top and bottom
		if (currMouse.v >= tbRect.top && currMouse.v <= tbRect.bottom)
		{
			thickness = origThickness + currMouse.h - inWhere.h;
			if (thickness < blThicknessResizeMin) thickness = blThicknessResizeMin;
			else if (thickness > max) thickness = max;
			(void)BLSetColumnWidth( 0, thickness, inList );
		}
	}
}

#pragma mark -
#pragma mark ¥¥¥Metrics¥¥¥
//===============================
// Converts a mouse location to the number of a title.
// Assumes that BLPointIn(x)TitleBar has been called and returned true.
UInt16 _BLPointToTitle( Point inWhere, BLTitleBarHdl inBar, BlugsRef inList )
{
	UInt16		title = 0, i;
	Rect		viewRect;
	
	viewRect = _BLViewRect( inList );
	if (!bl_BarVert(inBar))
	{
		UInt16		nCols;
		
		nCols = bl_NCols(inList);
		if (nCols)
		{
			BLPixelOffset	offsetFromLeft;
			
			// Relation between cursor and left of title bar
			offsetFromLeft = bl_HScrollLoc(inList) + inWhere.h - viewRect.left;
			for (i = 1; i <= nCols; i++)
			{
				UInt32		cRight;
				
				cRight = _BLColumnRight( i, inList );
				if (cRight > offsetFromLeft)
				{
					title = i;
					break;
				}
			}
		}
	}
	else
	{
		UInt16		nRows;
		
		nRows = bl_NRows(inList);
		if (nRows)
		{
			BLPixelOffset	offsetFromTop;
			
			offsetFromTop = bl_VScrollLoc(inList) + inWhere.v - viewRect.top;
			for (i = 1; i <= nRows; i++)
			{
				UInt32			rBottom;
				
				rBottom = _BLRowBottom( i, inList );
				if (rBottom > offsetFromTop)
				{
					title = i;
					break;
				}
			}
		}
	}
	return title;
}

//===============================
// Notes: topLeft is either the top edge or the left edge of the title to be dropped, in local coords.
UInt16 _BLPointToDropHTitle( SInt16 topLeft, UInt16 draggingTitle, BLTitleBarHdl theBar, BlugsRef inList )
{
	OSErr		err;
	Rect		titleRect;
	
	err = _BLTitleRect( draggingTitle, theBar, &titleRect, inList );
	if (!err)
	{
		SInt32		returnValue, nTitles;
		SInt32		offset;
		Rect		tempRect;
		
		nTitles = bl_NCols( inList );
		if ( topLeft > titleRect.left )
		{
			// Check right edge position.
			offset = topLeft + bl_Width(titleRect) - 1;
			for ( returnValue = draggingTitle + 1; returnValue <= nTitles; returnValue++ )
			{
				err = _BLTitleRect( returnValue, theBar, &tempRect, inList );
				if (!err && offset < (tempRect.right + tempRect.left) / 2 ) return returnValue - 1;
			}
			return nTitles;
		}
		else if ( topLeft < titleRect.left )
		{
			// Check left edge position.
			offset = topLeft + 1;
			for ( returnValue = draggingTitle - 1; returnValue > 0; returnValue-- )
			{
				err = _BLTitleRect( returnValue, theBar, &tempRect, inList );
				if (!err && offset > (tempRect.right + tempRect.left) / 2) return returnValue + 1;
			}
			return 1;
		}
	}
	return draggingTitle;
}


//===============================
// Notes: topLeft is either the top edge or the left edge of the title to be dropped, in local coords.
UInt16 _BLPointToDropVTitle( SInt16 inTopLeft, UInt16 inTitle, BLTitleBarHdl inBar, BlugsRef inList )
{
	OSErr		err;
	Rect		titleRect;
	
	err = _BLTitleRect( inTitle, inBar, &titleRect, inList );
	if (!err)
	{
		SInt32			returnValue, nTitles;
		SInt32			offset;
		Rect			tempRect;
		SInt32			skippedTitles = 0;
		UInt16			parentRow;
		
		nTitles = bl_NRows( inList );
		if ( inTopLeft > titleRect.top )
		{
			// Check bottom edge position.
			offset = inTopLeft + bl_Height(titleRect) - 1;

			for ( returnValue = inTitle + 1; returnValue <= nTitles; returnValue++ ) {
				err = _BLTitleRect( returnValue, inBar, &tempRect, inList );
				if ( err || tempRect.bottom == tempRect.top )
					skippedTitles++;
				else if ( offset < (tempRect.bottom + tempRect.top) / 2 ) {
					// Make sure that we don't move into our children.
					parentRow = BLGetParentRow( returnValue - 1, inList );
					if ( parentRow == inTitle || ( returnValue - 1 ) == inTitle)
						return inTitle;
					else
						return returnValue - 1;
				}
			}

			return nTitles;

		}
		else if ( inTopLeft < titleRect.bottom )
		{
			// Check top edge position.
			offset = inTopLeft + 1;
			for ( returnValue = inTitle - 1; returnValue > 0; returnValue-- )
			{
				err = _BLTitleRect( returnValue, inBar, &tempRect, inList );
				if (err || tempRect.bottom == tempRect.top) skippedTitles++;
				else if ( offset > (tempRect.bottom + tempRect.top) / 2 ) return returnValue + 1;
			}
			return 1;
		}
	}
	return inTitle;
}

//===============================
Rect _BLTitleBarRect( BLTitleBarHdl inBar, BlugsRef inList )
{
	Rect			r;
	Boolean			vert;
	UInt16			thickness;
	BLTitleBarHdl	theOtherBar;
	
	r = _BLOffscreenRect( inList ); // Don't want to take into account scroll bars
	vert = bl_BarVert(inBar);
	thickness = (*inBar)->thickness;
	if (vert)
	{
		theOtherBar = bl_HTitle(inList);
		if (theOtherBar) r.top += (*theOtherBar)->thickness;
		r.right = r.left + thickness;
	}
	else
	{
		theOtherBar = bl_VTitle(inList);
		if (theOtherBar) r.left += (*theOtherBar)->thickness;
		r.bottom = r.top + thickness;
	}
	return r;
}

//===============================
// If there is blank space between the rightmost column and the list edge,
//	it interrupts the bar. We draw a nice inert extension to plug the hole.
// Note that if there are no rows/columns the whole thing is unclaimed!
Boolean _BLTitleBarUnclaimedRect( Boolean inVertical, BLTitleBarHdl inBar, Rect* outRect,
									BlugsRef inList )
{
	Rect		lastTitleRect, offscreenRect;
	Boolean		isBlankSpace = false;
	OSErr		err;
	
	offscreenRect = _BLOffscreenRect( inList );
	if (inVertical)
	{
		UInt16	nRows;
		
		nRows = bl_NRows(inList);
		if (!nRows)
		{
			*outRect = _BLTitleBarRect( inBar, inList );
			isBlankSpace = true;
		}
		else
		{
			err = _BLTitleRect( nRows, inBar, &lastTitleRect, inList );
			if (!err && lastTitleRect.bottom < offscreenRect.bottom)
			{
				lastTitleRect.top = lastTitleRect.bottom;
				lastTitleRect.bottom = offscreenRect.bottom;
				*outRect = lastTitleRect;
				isBlankSpace = true;
			}
		}
	}
	else
	{
		UInt16	nCols;
		
		nCols = bl_NCols(inList);
		if (!nCols)
		{
			*outRect = _BLTitleBarRect( inBar, inList );
			isBlankSpace = true;
		}
		else
		{
			err = _BLTitleRect( nCols, inBar, &lastTitleRect, inList );
			if (!err && lastTitleRect.right < offscreenRect.right)
			{
				lastTitleRect.left = lastTitleRect.right;
				lastTitleRect.right = offscreenRect.right;
				*outRect = lastTitleRect;
				isBlankSpace = true;
			}
		}
	}
	return isBlankSpace;
}

//===============================
OSErr _BLTitleRect( UInt16 inTitle, BLTitleBarHdl inBar, Rect* outRect, BlugsRef inList )
{
	Rect	r;
	OSErr	err = noErr;
	
	if (!inTitle)
	{
		BLTitleBarHdl	vTitle, hTitle;
		
		// Get rect for top left title.
		vTitle = bl_VTitle(inList);
		hTitle = bl_HTitle(inList);
		if (vTitle && hTitle)
		{
			Rect		listRect = bl_Rect(inList);
			
			r.left = listRect.left;
			r.right = r.left + (*vTitle)->thickness;
			r.top = listRect.top;
			r.bottom = r.top + (*hTitle)->thickness;
		}
		else err = inputOutOfBounds;
	}
	else
	{
		UInt16	thickness = (*inBar)->thickness;
		
		r = bl_Rect(inList);
		if (bl_BarVert(inBar))
		{
			r.right = r.left + thickness;
			err = _BLRowTopBottom( inTitle, &r.top, &r.bottom, inList );
		}
		else
		{
			r.bottom = r.top + thickness;
			err = _BLColumnLeftRight( inTitle, &r.left, &r.right, inList );
		}
	}
	*outRect = r;
	return err;
}

