/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ // // Implementation of the table that is the main component of the personal toolbar. // #include #include #include "CPersonalToolbarTable.h" #include "CPersonalToolbarManager.h" #include "uapp.h" #include "LTableMultiGeometry.h" #include "CURLDragHelper.h" #include "macutil.h" #include "CIconTextDragTask.h" #include "resgui.h" #include "URDFUtilities.h" #include "miconutils.h" #include "UMemoryMgr.h" static const RGBColor blue = { 0, 0, 0xFFFF }; static const RGBColor black = { 0, 0, 0 }; static const RGBColor bgColor = { 0xDDDD, 0xDDDD, 0xDDDD }; DragSendDataUPP CPersonalToolbarTable::sSendDataUPP; CPersonalToolbarTable :: CPersonalToolbarTable ( LStream* inStream ) : LSmallIconTable(inStream), LDragAndDrop ( GetMacPort(), this ), mDropCol(LArray::index_Bad), mHiliteCol(LArray::index_Bad), mDropOn(false) { // LSmallIconTable wants to use a LTableSingleGeometry, but since we want the toolbar // to have variable column widths, replace it with a multiGeometry implementation if ( mTableGeometry ) { delete mTableGeometry; mTableGeometry = new LTableMultiGeometry ( this, mFrameSize.width, 20 ); } } // constructor CPersonalToolbarTable :: ~CPersonalToolbarTable ( ) { CFrontApp::GetPersonalToolbarManager()->RemoveListener(this); //ее dispose drag routine descriptor } // destructor // // FinishCreateSelf // void CPersonalToolbarTable :: FinishCreateSelf ( ) { InsertRows ( 1, 1, NULL, 0, false ); CFrontApp::GetPersonalToolbarManager()->RegisterNewToolbar(this); if ( !sSendDataUPP) { sSendDataUPP = NewDragSendDataProc(LDropArea::HandleDragSendData); ThrowIfNil_(sSendDataUPP); } } // FinishCreateSelf // // FillInToolbar // // Add rows to the table based on the bookmark information in the manager object. This will try to give each // column as much space as possible on the fly. Don't make any assumptions about the incoming // text mode...be paranoid! // void CPersonalToolbarTable :: FillInToolbar ( ) { const Uint32 kPadRight = 15; const Uint32 kBMIconWidth = 28; const Uint32 kButtonCount = CFrontApp::GetPersonalToolbarManager()->GetButtons().GetCount(); const Uint32 kMaxLength = CFrontApp::GetPersonalToolbarManager()->GetMaxToolbarButtonChars(); const Uint32 kMinLength = CFrontApp::GetPersonalToolbarManager()->GetMinToolbarButtonChars(); StTextState saved; UTextTraits::SetPortTextTraits(kTextTraitsID); // // create an array that holds the # of characters currently in each column. Initialize this with // the min column size (specified in prefs), or less if the title has less chars. // Uint16* widthArray = new Uint16[kButtonCount]; Uint16 totalWidth = 0; CUserButtonInfo* curr; Uint32 widthArrayIter = 0; LArrayIterator it ( CFrontApp::GetPersonalToolbarManager()->GetButtons() ); while ( it.Next(&curr) ) { Uint16 numChars = min ( kMinLength, curr->GetName().length() ); widthArray[widthArrayIter] = numChars; totalWidth += ::TextWidth(curr->GetName().c_str(), 0, numChars) + kBMIconWidth; // extend the total... widthArrayIter++; } // initialize each item InsertCols ( kButtonCount, 0, NULL, 0, false ); // compute how much room we have left to divvy out after divvying out the minimum above. Leave // a few pixels on the right empty... int16 emptySpace = (mFrameSize.width - kPadRight) - totalWidth; // // divvy out space to each column, one character at a time to each column // while ( emptySpace > 0 ) { bool updated = false; Uint32 i = 0; LArrayIterator it2 ( CFrontApp::GetPersonalToolbarManager()->GetButtons() ); while ( it2.Next(&curr) ) { if ( emptySpace && widthArray[i] < curr->GetName().length() && widthArray[i] < kMaxLength ) { // subtract off the single character we're adding to the column char addedChar = curr->GetName()[widthArray[i]]; emptySpace -= ::TextWidth(&addedChar, 0, 1); widthArray[i]++; updated = true; // we found something to add, allow us to continue } i++; } // for each column // prevent infinite looping if no column can be expanded and we still have extra room remaining if ( !updated ) break; } // while space remains to divvy out // // assign the widths to the columns and set the data in the columns. // STableCell where (1, 1); widthArrayIter = 0; LArrayIterator it3 ( CFrontApp::GetPersonalToolbarManager()->GetButtons() ); while ( it3.Next(&curr) ) { string bmText = curr->GetName(); Uint32 textLength = bmText.length(); // // fill in the cell with the name of the bookmark and set the column width to // the width of the string. If the name is longer than the max, chop it. // SIconTableRec data; Uint16 dispLength = widthArray[widthArrayIter]; ::BlockMove ( bmText.c_str(), &data.name[1], dispLength + 1 ); data.name[0] = dispLength <= kMaxLength ? dispLength : kMaxLength; data.iconID = curr->IsFolder() ? kFOLDER_ICON : kBOOKMARK_ICON; SetCellData ( where, &data, sizeof(SIconTableRec) ); Uint32 pixelWidth = ::TextWidth(bmText.c_str(), 0, dispLength)+ kBMIconWidth; mTableGeometry->SetColWidth ( pixelWidth, where.col, where.col ); widthArrayIter++; where.col++; // next column, please.... } // for each bookmark in the folder Refresh(); delete[] widthArray; } // FillInToolbar // // MouseLeave // // Called when the mouse leaves the personal toolbar. Redraw the previous selection to get rid // of the blue text color. // void CPersonalToolbarTable :: MouseLeave ( ) { STableCell refresh(1, mHiliteCol); mHiliteCol = LArray::index_Bad; StClipRgnState savedClip; FocusDraw(); RedrawCellWithTextClipping ( refresh ); } // MouseLeave // // MouseWithin // // Called while the mouse moves w/in the personal toolbar. Find which cell the mouse is // currently over and remember it. If we've moved to a different cell, make sure to // refresh the old one so it is drawn normally. // void CPersonalToolbarTable :: MouseWithin ( Point inPortPt, const EventRecord& ) { // get the previous selection STableCell old(1, mHiliteCol); SPoint32 imagePt; PortToLocalPoint(inPortPt); LocalToImagePoint(inPortPt, imagePt); STableCell hitCell; if ( GetCellHitBy(imagePt, hitCell) ) if ( old != hitCell ) { StClipRgnState savedClip; mHiliteCol = hitCell.col; FocusDraw(); if ( old.col ) RedrawCellWithTextClipping(old); if ( hitCell.col ) RedrawCellWithTextClipping(hitCell); ExecuteAttachments(msg_HideTooltip, this); // hide tooltip } } // MouseWithin // // Click // // Allow drags to occur when another window is in front of us. // void CPersonalToolbarTable :: Click ( SMouseDownEvent& inMouseDown ) { PortToLocalPoint(inMouseDown.whereLocal); UpdateClickCount(inMouseDown); if (ExecuteAttachments(msg_Click, &inMouseDown)) { ClickSelf(inMouseDown); } } #if 0 // // Click // // Overridden to handle clase of drag and drop when communicator is in the background. Code // copied from CWPro1 CD sample code (CDragAndDropTable.cp). // // FOR SOME REASON, THIS DOESN'T WORK....DUNNO WHY... void CPersonalToolbarTable :: Click ( SMouseDownEvent& inMouseDown ) { if ( inMouseDown.delaySelect && DragAndDropIsPresent() ) { // In order to support dragging from an inactive window, // we must explicitly test for delaySelect and the // presence of Drag and Drop. // Convert to a local point. PortToLocalPoint( inMouseDown.whereLocal ); // Execute click attachments. if ( ExecuteAttachments( msg_Click, &inMouseDown ) ) { // Handle the actual click event. ClickSelf( inMouseDown ); } } else { // Call inherited for default behavior. LTableView::Click( inMouseDown ); } } // Click #endif // // ClickSelect // // Override to always say that we can be selected, because there is no concept of selection // in this toolbar. Boolean CPersonalToolbarTable :: ClickSelect( const STableCell &/*inCell*/, const SMouseDownEvent &/*inMouseDown*/) { return true; } // // ClickCell // // Override the default behavior of selecting a cell to open the url associated with the bookmark // there. // void CPersonalToolbarTable :: ClickCell(const STableCell &inCell, const SMouseDownEvent &inMouseDown) { if ( ::WaitMouseMoved(inMouseDown.macEvent.where) ) { if (LDropArea::DragAndDropIsPresent()) { mDraggedCell = inCell; // save which cell is being dragged for later // create the drag task Rect bounds; GetLocalCellRect ( inCell, bounds ); CUserButtonInfo* data = GetButtonInfo ( inCell.col ); string finalCaption = CURLDragHelper::MakeIconTextValid ( data->GetName().c_str() ); HT_Resource node = HT_GetNthItem(CFrontApp::GetPersonalToolbarManager()->GetHTView(), URDFUtilities::PPRowToHTRow(inCell.col)); CIconTextSuite suite ( this, bounds, kBOOKMARK_ICON, finalCaption, node ); CIconTextDragTask theTask(inMouseDown.macEvent, &suite, bounds); // setup our special data transfer proc called upon drag completion OSErr theErr = ::SetDragSendProc ( theTask.GetDragReference(), sSendDataUPP, (LDropArea*) this ); ThrowIfOSErr_(theErr); theTask.DoDrag(); // remove the url if it went into the trash if ( theTask.DropLocationIsFinderTrash() ) CFrontApp::GetPersonalToolbarManager()->RemoveButton ( inCell.col ); } // if d&d allowed } // if drag else { CUserButtonInfo* data = GetButtonInfo ( inCell.col ); // code for context menu here, if appropriate.... if ( data->IsFolder() ) { SysBeep(1); } else { CUserButtonInfo* clicked = GetButtonInfo ( inCell.col ); CFrontApp::DoGetURL( clicked->GetURL().c_str()); } } // else just a click } // ClickCell // // RedrawCellWithHilite // // A helpful utility routine that wraps DrawCell() with calls to setup the drawing params // appropriately. When redrawing a cell during a drag and drop, call this routine instead // of calling DrawCell directly. // void CPersonalToolbarTable :: RedrawCellWithHilite ( const STableCell inCell, bool inHiliteOn ) { Rect localCellRect; GetLocalCellRect ( inCell, localCellRect ); // since mDropOn is used as the flag in DrawCell() for whether or not we want to // draw the hiliting on the cell, save its value and set it to what was passed in // before calling DrawCell(). StValueChanger oldHilite(mDropOn, inHiliteOn); //еее won't link with bool type =( // if the hiliting is being turned off, erase the cell so it draws normally again if ( !inHiliteOn ) { StColorState saved; ::RGBBackColor(&bgColor); ::EraseRect(&mTextHiliteRect); // we can be sure this has been previously computed } DrawCell ( inCell, localCellRect ); } // RedrawCellWithHilite // // DrawCell // // Override to draw differently when this is the selected cell. Otherwise, pass it back // to the inherited routine to draw normally. // void CPersonalToolbarTable :: DrawCell ( const STableCell &inCell, const Rect &inLocalRect ) { StTextState savedText; StColorPenState savedColor; ::RGBForeColor(&black); SIconTableRec iconAndName; Uint32 dataSize = sizeof(SIconTableRec); GetCellData(inCell, &iconAndName, dataSize); Rect iconRect; iconRect.left = inLocalRect.left + 3; iconRect.right = iconRect.left + 16; iconRect.bottom = inLocalRect.bottom - 2; iconRect.top = iconRect.bottom - 16; IconTransformType transform = kTransformNone; if ( mDropOn ) // handle drop on folder transform = kTransformSelected; ::PlotIconID(&iconRect, atNone, transform, iconAndName.iconID); UTextTraits::SetPortTextTraits(kTextTraitsID); if ( mDropOn ) { // handle drop on folder mTextHiliteRect = ComputeTextRect ( iconAndName, inLocalRect ); StColorState savedColorForTextDrawing; ::RGBBackColor(&black); ::EraseRect(&mTextHiliteRect); ::TextMode(srcXor); } else if ( mHiliteCol == inCell.col ) { TextFace(underline); RGBForeColor( &blue ); } ::MoveTo(inLocalRect.left + 22, inLocalRect.bottom - 4); ::DrawString(iconAndName.name); } // DrawCell // // ListenToMessage // // Handle broadcasts from the manager object, such as the personal toolbar folder being // changed or bookmarks being added/deleted/moved. // void CPersonalToolbarTable :: ListenToMessage ( MessageT inMessage, void* /*ioPtr*/ ) { switch ( inMessage ) { case CPersonalToolbarManager::k_PTToolbarChanged: if ( mCols ) RemoveCols ( mCols, 1, false ); // out with the old... FillInToolbar(); break; } // case of which message } // ListenToMessage // // DoDragSendData // // When the drag started, the ClickCell() routine cached which cell was the start of the drag in // |mDraggedCell|. Extract the URL and Title from this cell and pass it along to the helper // routine from CURLDragHelper // void CPersonalToolbarTable :: DoDragSendData( FlavorType inFlavor, ItemReference inItemRef, DragReference inDragRef) { CUserButtonInfo* dragged = GetButtonInfo ( mDraggedCell.col ); CURLDragHelper::DoDragSendData ( dragged->GetURL().c_str(), const_cast(dragged->GetName().c_str()), inFlavor, inItemRef, inDragRef ); } // DoDragSendData // // HiliteDropArea // // Show that this toolbar is a drop site for urls // void CPersonalToolbarTable :: HiliteDropArea ( DragReference inDragRef ) { Rect frame; CalcLocalFrameRect ( frame ); // show the drag hilite in drop area RgnHandle rgn = ::NewRgn(); ThrowIfNil_(rgn); ::RectRgn ( rgn, &frame ); ::ShowDragHilite ( inDragRef, rgn, true ); ::DisposeRgn ( rgn ); } // HiliteDropArea // // InsideDropArea // // Called repeatedly while mouse is inside this during a drag. For each column, the cell // can be divided into several sections. // void CPersonalToolbarTable :: InsideDropArea ( DragReference inDragRef ) { FocusDraw(); Point mouseLoc; SPoint32 imagePt; ::GetDragMouse(inDragRef, &mouseLoc, NULL); ::GlobalToLocal(&mouseLoc); LocalToImagePoint(mouseLoc, imagePt); Rect localRect; TableIndexT colMouseIsOver = mTableGeometry->GetColHitBy(imagePt); GetLocalCellRect ( STableCell(1, colMouseIsOver), localRect ); TableIndexT newDropCol; bool newDropOn = false; CUserButtonInfo* info = GetButtonInfo(colMouseIsOver); if ( info ) { if ( info->IsFolder() ) { Rect leftSide, rightSide; ComputeFolderDropAreas ( localRect, leftSide, rightSide ); if ( ::PtInRect(mouseLoc, &leftSide) ) newDropCol = colMouseIsOver; // before this cell else if ( ::PtInRect(mouseLoc, &rightSide) ) newDropCol = colMouseIsOver + 1; // after this cell else { newDropCol = colMouseIsOver; newDropOn = true; // hilite folder, don't draw line } } else { // draw line between rows Rect leftSide, rightSide; ComputeItemDropAreas ( localRect, leftSide, rightSide ); if ( ::PtInRect(mouseLoc, &leftSide) ) newDropCol = colMouseIsOver; // before this cell else newDropCol = colMouseIsOver + 1; // after this cell } } // if drag over existing column else { // else drag over empty part of toolbar newDropCol = mCols + 1; } // if something has changed, redraw as necessary if ( newDropCol != mDropCol || newDropOn != mDropOn ) { // unhilight old one (if necessary) if ( mDropOn ) RedrawCellWithHilite( STableCell(1, mDropCol), false ); else if ( mDropCol > 0 ) DrawDividingLine ( mDropCol ); mDropCol = newDropCol; mDropOn = newDropOn; // hilight new one if ( mDropOn ) RedrawCellWithHilite ( STableCell(1, mDropCol), true ); else DrawDividingLine ( newDropCol ); } // if mouse moved to another drop location } // InsideDropArea // // LeaveDropArea // // Clean up the drop feedback stuff when the mouse leaves the area // void CPersonalToolbarTable :: LeaveDropArea( DragReference inDragRef ) { FocusDraw(); // if we were hiliting a folder, redraw it without the hiliting. If we were drawing a // line, undraw it. if ( mDropOn ) RedrawCellWithHilite ( STableCell(1,mDropCol), false ); else DrawDividingLine( mDropCol ); mDropCol = LArray::index_Bad; mDropOn = false; // Call inherited. LDragAndDrop::LeaveDropArea( inDragRef ); } // // ComputeItemDropAreas // // When a drag goes over a cell that contains a single node, divide the node in half. The left // side will represent dropping before the node, the right side after. // void CPersonalToolbarTable :: ComputeItemDropAreas ( const Rect & inLocalCellRect, Rect & oLeftSide, Rect & oRightSide ) { oRightSide = oLeftSide = inLocalCellRect; uint16 midPt = (oLeftSide.right - oLeftSide.left) / 2; oLeftSide.right = oLeftSide.left + midPt; oRightSide.left = oLeftSide.left + midPt + 1; } // ComputeItemDropAreas // // ComputeFolderDropAreas // // When a drag goes over a cell that contains a folder, divide the cell area into 3 parts. The middle // area, which corresponds to a drop on the folder takes up the majority of the cell space with the // left and right areas (corresponding to drop before and drop after, respectively) taking up the rest // at the ends. // void CPersonalToolbarTable :: ComputeFolderDropAreas ( const Rect & inLocalCellRect, Rect & oLeftSide, Rect & oRightSide ) { // make sure the left/right area widths aren't too big for the cell Uint16 endAreaWidth = 20; if ( inLocalCellRect.right - inLocalCellRect.left < 50 ) endAreaWidth = 5; oRightSide = oLeftSide = inLocalCellRect; oLeftSide.right = oLeftSide.left + endAreaWidth; oRightSide.left = oRightSide.right - endAreaWidth; } // ComputeFolderDropAreas // // DrawDividingLine // // Draws a vertical black line before the given column in the toolbar (or undraws if one // is already there). If the column given is after the right edge of the last column, it // draws after the last column (as the user expects). // void CPersonalToolbarTable :: DrawDividingLine( TableIndexT inCol ) { Uint32 numItems = CFrontApp::GetPersonalToolbarManager()->GetButtons().GetCount(); if ( !numItems ) // don't draw anything if toolbar empty return; // Setup the target cell. STableCell theCell; theCell.row = 1; theCell.col = inCol; // find the boundary of the cell we're supposed to be drawing the line before. If // the incoming column is at the end (greater than the # of buttons) then hack up // a boundary rect to draw after the last column. Rect cellBounds; if ( inCol > numItems ) { // get the boundary of the last column theCell.col = numItems; GetLocalCellRect ( theCell, cellBounds ); // make the left edge of our fake column the right edge of the last column cellBounds.left = cellBounds.right; } else GetLocalCellRect ( theCell, cellBounds ); // Focus the pane and get the table and cell frames. Rect theFrame; if ( FocusDraw() && CalcLocalFrameRect( theFrame ) ) { // Save the draw state and clip the list view rect. StColorPenState theDrawState; StClipRgnState theClipState( theFrame ); // Setup the color and pen state then draw the line ::ForeColor( blackColor ); ::PenMode( patXor ); ::PenSize( 2, 2 ); ::MoveTo( cellBounds.left, cellBounds.top ); ::LineTo( cellBounds.left, cellBounds.bottom ); } } // DrawDividingLine // // FindBestFlavor // // Scan through the list of acceptable flavors and find the best one that is contained // in the given drag item. Returns true if it found one in the list and false if the // drag item doesn't contain any of the desired flavors. // bool CPersonalToolbarTable :: FindBestFlavor ( DragReference inDragRef, ItemReference inItemRef, FlavorType & oFlavor ) { static FlavorType flavors[] = { emHTNodeDrag, emBookmarkDrag, NULL }; // must end in NULL oFlavor = '****'; short i = 0; for ( FlavorType curr = flavors[0]; flavors[i]; i++, curr = flavors[i] ) { FlavorFlags theFlags; if ( ::GetFlavorFlags(inDragRef, inItemRef, curr, &theFlags) == noErr ) { oFlavor = curr; return true; } } // for each flavor in list return false; } // FindBestFlavor // // ItemIsAcceptable // // If FindBestFlavor() finds an acceptable flavor, then this item can be accepted. If not, it // can't. We don't really care at this point what that flavor is. // Boolean CPersonalToolbarTable :: ItemIsAcceptable ( DragReference inDragRef, ItemReference inItemRef ) { FlavorType ignored; return FindBestFlavor ( inDragRef, inItemRef, ignored ); } // ItemIsAcceptable // // ReceiveDragItem // // Called for each item dropped on the table. Create a new bookmark in the PT folder for // each item // void CPersonalToolbarTable :: ReceiveDragItem ( DragReference inDragRef, DragAttributes /*inDragAttrs*/, ItemReference inItemRef, Rect & /*inItemBounds*/ ) { FlavorType flavorToUse; FindBestFlavor ( inDragRef, inItemRef, flavorToUse ); // ok to ignore return result // Get the data. Size theDataSize; ThrowIfOSErr_( ::GetFlavorDataSize(inDragRef, inItemRef, flavorToUse, &theDataSize) ); switch ( flavorToUse ) { case emHTNodeDrag: HT_Resource node; ThrowIfOSErr_( ::GetFlavorData( inDragRef, inItemRef, flavorToUse, &node, &theDataSize, 0 ) ); if ( mDropOn ) { SysBeep(1); //еее implement } else CFrontApp::GetPersonalToolbarManager()->AddButton ( node, mDropCol ); break; case emBookmarkDrag: vector urlAndTitle ( theDataSize + 1 ); ThrowIfOSErr_( ::GetFlavorData( inDragRef, inItemRef, flavorToUse, urlAndTitle.begin(), &theDataSize, 0 ) ); urlAndTitle[theDataSize] = NULL; char* title = find(urlAndTitle.begin(), urlAndTitle.end(), '\r'); if ( title != urlAndTitle.end() ) { title[0] = NULL; title++; char* url = urlAndTitle.begin(); if ( mDropOn ) { SysBeep(1); //еее implement } else CFrontApp::GetPersonalToolbarManager()->AddButton ( url, title, mDropCol ); } break; } // case of which flavor } // ReceiveDragItem // // GetButtonInfo // // fetch cell data given a column #. // CUserButtonInfo* CPersonalToolbarTable :: GetButtonInfo ( Uint32 inColumn ) { CUserButtonInfo* temp = nil; CFrontApp::GetPersonalToolbarManager()->GetButtons().FetchItemAt (inColumn, &temp ); return temp; } // GetButtonInfo void CPersonalToolbarTable :: FindTooltipForMouseLocation ( const EventRecord& inMacEvent, StringPtr outTip ) { Point temp = inMacEvent.where; SPoint32 where; GlobalToPortPoint(temp); PortToLocalPoint(temp); LocalToImagePoint(temp, where); STableCell hitCell; if ( GetCellHitBy(where, hitCell) && hitCell.col <= mCols ) { CUserButtonInfo* bkmk = GetButtonInfo(hitCell.col); outTip[0] = bkmk->GetName().length(); strcpy ( (char*) &outTip[1], bkmk->GetName().c_str() ); } else ::GetIndString ( outTip, 10506, 12); // supply a helpful message... } // FindTooltipForMouseLocation void CPersonalToolbarTable :: ResizeFrameBy ( Int16 inWidth, Int16 inHeight, Boolean inRefresh ) { LSmallIconTable::ResizeFrameBy(inWidth, inHeight, inRefresh); ListenToMessage ( CPersonalToolbarManager::k_PTToolbarChanged, nil ); } // ResizeFrameTo // // ComputeTextRect // // Compute the area of the text rectangle so we can clip to it on redraw // Rect CPersonalToolbarTable :: ComputeTextRect ( const SIconTableRec & inText, const Rect & inLocalRect ) { Rect textRect; uint16 width = ::TextWidth(inText.name, 1, *inText.name); textRect.left = inLocalRect.left + 20; textRect.right = textRect.left + width + 2; textRect.bottom = inLocalRect.bottom - 1; textRect.top = inLocalRect.top + 1; return textRect; } // ComputeTextRect // // RedrawCellWithTextClipping // // A pretty way to redraw the cell because it won't flash. This sets the clip region to the // text that needs to be redrawn so it looks fast to the user. // // NOTE: This blows away the current clip region so if you care, you must restore it afterwards. I // don't do it here because you may want to make a couple of these calls in a row and restoring the // clip rect in between would be a waste. It also blows away the background color. // void CPersonalToolbarTable :: RedrawCellWithTextClipping ( const STableCell & inCell ) { StTextState savedText; SIconTableRec iconAndName; Rect localRect; UTextTraits::SetPortTextTraits(kTextTraitsID); Uint32 dataSize = sizeof(SIconTableRec); GetCellData(inCell, &iconAndName, dataSize); GetLocalCellRect ( inCell, localRect ); Rect textRect = ComputeTextRect(iconAndName,localRect); ::ClipRect(&textRect); ::RGBBackColor(&bgColor); ::EraseRect(&textRect); DrawCell(inCell, localRect); } // RedrawCellWithTextClipping