/* -*- 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. */ // This file contains the implementations of the various Bookmark Quick // File classes. /** INCLUDE **/ #include "stdafx.h" #include "cxicon.h" #include "quickfil.h" #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif typedef struct { UINT nCommand; int nPosition; } MnemonicStruct; /**************************************************************************** * * Class: CTreeItem * * DESCRIPTION: * This class provides an abstract object for representing an item * within a hierarchical tree. * ****************************************************************************/ /**************************************************************************** * * CTreeItem::CTreeItem * * PARAMETERS: * pImg - image to be drawn with this item (NULL if none) * uID - unique item identifier * strLabel - text label for this item * * RETURNS: * N/A * * DESCRIPTION: * Constructor. * ****************************************************************************/ CTreeItem::CTreeItem(CBitmap * pUnselectedImg, CBitmap *pSelectedImg, const UINT uID, const CString & strLabel, CMenu *pSubMenu) { m_pUnselectedImg = pUnselectedImg; m_pSelectedImg = pSelectedImg; m_uID = uID; m_strLabel = strLabel; m_unselectedBitmapSize.cx = m_unselectedBitmapSize.cy = 0; m_selectedBitmapSize.cx = m_selectedBitmapSize.cy = 0; m_textSize.cx = m_textSize.cy = 0; m_accelSize.cx = m_accelSize.cy =0; m_pSubMenu = pSubMenu; } // END OF FUNCTION CTreeItem::CTreeItem() /**************************************************************************** * * CTreeItem::~CTreeItem * * PARAMETERS: * N/A * * RETURNS: * N/A * * DESCRIPTION: * Destructor. * ****************************************************************************/ CTreeItem::~CTreeItem() { if(m_pSubMenu) delete m_pSubMenu; } // END OF FUNCTION CTreeItem::~CTreeItem() /**************************************************************************** * * Class: CTreeItemList * * DESCRIPTION: * This is a collection class for holding CTreeItem objects. * ****************************************************************************/ /**************************************************************************** * * CTreeItemList::CTreeItemList * * PARAMETERS: * None * * RETURNS: * N/A * * DESCRIPTION: * Constructor * ****************************************************************************/ CTreeItemList::CTreeItemList() { } // END OF FUNCTION CTreeItemList::CTreeItemList() /**************************************************************************** * * CTreeItemList::~CTreeItemList * * PARAMETERS: * N/A * * RETURNS: * N/A * * DESCRIPTION: * Destructor. We provide auto-cleanup for the objects in the collection. * ****************************************************************************/ CTreeItemList::~CTreeItemList() { int nCount = GetSize(); for (int i = 0; i < nCount; i++) { CTreeItem * pItem = Get(i); if (pItem != NULL) { delete pItem; } } RemoveAll(); } // END OF FUNCTION CTreeItemList::~CTreeItemList() /**************************************************************************** * * Class: CTreeMenu * * DESCRIPTION: * This class provides a custom, self drawing menu object for displaying * graphics as well as text in a menu item. * ****************************************************************************/ /**************************************************************************** * * CONSTANTS * ****************************************************************************/ static int nIMG_SPACE = 3; // Gap between image and text in menu item /**************************************************************************** * * CTreeMenu::CTreeMenu * * PARAMETERS: * None * * RETURNS: * N/A * * DESCRIPTION: * Constructor. * ****************************************************************************/ CTreeMenu::CTreeMenu() { m_WidestImage=0; m_WidestText=0; m_WidestAccelerator=0; m_pParent = NULL; } // END OF FUNCTION CTreeMenu::CTreeMenu() CTreeMenu::~CTreeMenu() { m_itemList.RemoveAll(); DeleteMnemonics(); } void CTreeMenu::DeleteMnemonics(void) { POSITION pos; WORD dwKey; MnemonicStruct *pMnemonic = NULL; // also destroy bitmaps; pos = m_mnemonicMap.GetStartPosition(); while(pos) { m_mnemonicMap.GetNextAssoc(pos, dwKey,(void *&)pMnemonic); delete pMnemonic; } m_mnemonicMap.RemoveAll(); } /**************************************************************************** * * CTreeMenu::AddItem * * PARAMETERS: * pItem - pointer to abstract item * hSubMenu - handle of sub-menu is this item is a new node * * RETURNS: * TRUE if successful. * * DESCRIPTION: * This function is called to add a new menu item to the main trunk. The * new item can also be a branch, if hSubMenu is set properly. *****************************************************************************/ BOOL CTreeMenu::AddItem(CTreeItem * pItem, int nPosition /*=0*/, CTreeMenu *pSubMenu /*= NULL*/, void* pIcon /* = NULL */, IconType nIconType /* = BUILTIN_BITMAP */) { BOOL bRtn = FALSE; m_itemList.Add(pItem); pItem->SetIcon(pIcon, nIconType); if (pSubMenu != NULL) { bRtn = InsertMenu(nPosition, MF_BYPOSITION | MF_OWNERDRAW | MF_POPUP, (UINT)pSubMenu->GetSafeHmenu(), (const char *)pItem); } else { bRtn = InsertMenu(nPosition, MF_BYPOSITION | MF_OWNERDRAW, pItem->GetID(), (const char *)pItem); } return(bRtn); } // END OF FUNCTION CTreeMenu::AddItem() CMenu * CTreeMenu::FindMenu(CString& menuName) { int nSize = m_itemList.GetSize(); for(int i = 0; i < nSize; i ++) { CTreeItem *pItem = (CTreeItem*)m_itemList[i]; if(pItem->GetLabel() == menuName) return pItem->GetSubMenu(); } return NULL; } /**************************************************************************** * * CTreeMenu::ClearItems * * PARAMETERS: * start: Clear all elements starting with this index * fromEnd: Delete up until this many elements from end * RETURNS: * N/A * * DESCRIPTION: * Removes all items from the itemList starting with start until * fromEnd elements from the end * ****************************************************************************/ void CTreeMenu::ClearItems(int start, int fromEnd) { m_itemList.RemoveAt(start, m_itemList.GetSize() - fromEnd - start); } void CTreeMenu::AddMnemonic(TCHAR cMnemonic, UINT nCommand, int nPosition) { MnemonicStruct *pMnemonic = new MnemonicStruct; pMnemonic->nCommand = nCommand; pMnemonic->nPosition = nPosition; m_mnemonicMap.SetAt(toupper(cMnemonic), pMnemonic); } BOOL CTreeMenu::GetMnemonic(TCHAR cMnemonic, UINT &nCommand, int &nPosition) { MnemonicStruct *pMnemonic; if(m_mnemonicMap.Lookup(toupper(cMnemonic), (void*&)pMnemonic) ) { nCommand = pMnemonic->nCommand; nPosition = pMnemonic->nPosition; return TRUE; } else return FALSE; } /**************************************************************************** * * CTreeMenu::CalculateItemDimensions * * PARAMETERS: * N/A * * RETURNS: * N/A * * DESCRIPTION: * For each item in the menu, this calculates the size of that item's * bitmap, menuitem text, and menuitem accelerator text. In addition, * this keeps track of the widest bitmap, text, and accelerator text in * the menu. This is done so that the accelerator can appear in a * reasonable position on the menu and assuring that enough space will * given to the menu item to draw itself * ****************************************************************************/ void CTreeMenu::CalculateItemDimensions(void) { CSize unselectedBitmapSize, selectedBitmapSize, textSize, acceleratorSize; CString label; m_WidestImage=0; m_WidestText=0; m_WidestAccelerator=0; int numItems = m_itemList.GetSize(); for(int i=0; iGetUnselectedImage()); item->SetUnselectedBitmapSize(unselectedBitmapSize); selectedBitmapSize=MeasureBitmap(item->GetSelectedImage()); item->SetSelectedBitmapSize(selectedBitmapSize); if(unselectedBitmapSize.cx > m_WidestImage) m_WidestImage = unselectedBitmapSize.cx; if(selectedBitmapSize.cx > m_WidestImage) m_WidestImage = selectedBitmapSize.cx; label = item->GetLabel(); //Figure out if there is an accelerator int tabPos=label.Find('\t'); if(tabPos!=-1) { textSize = MeasureText(label.Left(tabPos)); acceleratorSize = MeasureText(label.Right(label.GetLength() - (tabPos +1))); item->SetAcceleratorSize(acceleratorSize); if(acceleratorSize.cx > m_WidestAccelerator) m_WidestAccelerator = acceleratorSize.cx; } else textSize = MeasureText(label); if(textSize.cx > m_WidestText) m_WidestText = textSize.cx; item->SetTextSize(textSize); } } /**************************************************************************** * * CTreeMenu::MeasureBitmap * * PARAMETERS: * pBitmap: The bitmap to measure * * RETURNS: * The size of the bitmap * * DESCRIPTION: * Given a bitmap, this returns its dimensions * ****************************************************************************/ CSize CTreeMenu::MeasureBitmap(CBitmap *pBitmap) { CSize size; if (pBitmap != NULL) { BITMAP bmp; pBitmap->GetObject(sizeof(bmp), &bmp); size.cx = bmp.bmWidth; size.cy = bmp.bmHeight; } else size.cx = size.cy = 0; return size; } /**************************************************************************** * * CTreeMenu::MeasureText * * PARAMETERS: * text: The CString text to be measured * * RETURNS: * Returns the size of the text in the current font * * DESCRIPTION: * Given a CString this returns the dimensions of that text * ****************************************************************************/ CSize CTreeMenu::MeasureText(CString text) { HFONT MenuFont; #if defined(WIN32) NONCLIENTMETRICS ncm; ncm.cbSize = sizeof(NONCLIENTMETRICS); if (::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0)) { MenuFont = theApp.CreateAppFont( ncm.lfMenuFont ); } else { MenuFont = (HFONT)::GetStockObject(SYSTEM_FONT); } #else // Win16 MenuFont = (HFONT)::GetStockObject(SYSTEM_FONT); #endif // WIN32 CDC dc; dc.CreateCompatibleDC(NULL); CFont * pOldFont = dc.SelectObject(CFont::FromHandle(MenuFont)); CSize sizeTxt = dc.GetTabbedTextExtent((LPCSTR)text, strlen(text), 0, NULL); dc.SelectObject(pOldFont); return sizeTxt; } /**************************************************************************** * * CTreeMenu::MeasureItem * * PARAMETERS: * lpMI - pointer to LPMEASUREITEMSTRUCT * * RETURNS: * void * * DESCRIPTION: * We must override this function to inform the system of our menu * item dimensions, since we're owner draw style. * ****************************************************************************/ #define ACCELERATOR_TAB 5 //Leave some space between the text and the accelerator #define ACCELERATOR_RIGHT 15 //Leave a right margin between end of //menu item and end of accelerator #define MENU_LEFT_MARGIN 7 //Leave a left margin for text with no bitmaps void CTreeMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMI) { CTreeItem * pItem = (CTreeItem *)(lpMI->itemData); ASSERT(pItem != NULL); // First, get all of the dimensions CSize sizeUnselectedImg=pItem->GetUnselectedBitmapSize(); CSize sizeSelectedImg=pItem->GetSelectedBitmapSize(); CSize sizeText=pItem->GetTextSize(); CSize sizeAccelerator=pItem->GetAcceleratorSize(); //if there's no bitmap we need to provide a margin for the text lpMI->itemWidth = (m_WidestImage == 0) ? MENU_LEFT_MARGIN : 0; //Return the values depending upon whether there is an accelerator if(sizeAccelerator.cx !=0) { lpMI->itemWidth += m_WidestImage + m_WidestText + sizeAccelerator.cx + ACCELERATOR_TAB + ACCELERATOR_RIGHT + (2*nIMG_SPACE); } else lpMI->itemWidth += m_WidestImage + sizeText.cx + (nIMG_SPACE * 2); int nImageHeight = max(sizeUnselectedImg.cy, sizeSelectedImg.cy); lpMI->itemHeight = max(nImageHeight, sizeText.cy) + 4; } // END OF FUNCTION CTreeMenu::MeasureItem() /**************************************************************************** * * CTreeMenu::DrawItem * * PARAMETERS: * lpDI - pointer to LPDRAWITEMSTRUCT * * RETURNS: * void * * DESCRIPTION: * We must override this function to draw our image and text for the * menu item, since we're owner draw style. * ****************************************************************************/ void CTreeMenu::DrawItem(LPDRAWITEMSTRUCT lpDI) { // Extract the goods from lpDI CTreeItem * pItem = (CTreeItem *)(lpDI->itemData); ASSERT(pItem != NULL); CDC * pDC = CDC::FromHandle(lpDI->hDC); CRect rc(&(lpDI->rcItem)); // Get proper colors and paint the background first CBrush brBG; COLORREF rgbTxt; if (lpDI->itemState & ODS_SELECTED) { brBG.CreateSolidBrush(::GetSysColor(COLOR_HIGHLIGHT)); rgbTxt = ::GetSysColor(COLOR_HIGHLIGHTTEXT); } else { brBG.CreateSolidBrush(::GetSysColor(COLOR_MENU)); rgbTxt = ::GetSysColor(COLOR_MENUTEXT); } pDC->FillRect(&rc, &brBG); // Now paint the bitmap, left side of menu rc.left += nIMG_SPACE; CSize imgSize = DrawImage(pDC, rc, pItem, lpDI->itemState & ODS_SELECTED); // And now the text HFONT MenuFont; #if defined(WIN32) NONCLIENTMETRICS ncm; ncm.cbSize = sizeof(NONCLIENTMETRICS); if (::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0)) { MenuFont = theApp.CreateAppFont( ncm.lfMenuFont ); } else { MenuFont = (HFONT)::GetStockObject(SYSTEM_FONT); } #else // Win16 MenuFont = (HFONT)::GetStockObject(SYSTEM_FONT); #endif // WIN32 CFont * pOldFont = pDC->SelectObject(CFont::FromHandle(MenuFont)); int nOldBkMode = pDC->SetBkMode(TRANSPARENT); COLORREF rgbOldTxt = pDC->SetTextColor(rgbTxt); //Figure out where text should go in relation to bitmaps if(m_WidestImage == 0) rc.left += MENU_LEFT_MARGIN; rc.left += imgSize.cx + nIMG_SPACE + (m_WidestImage-imgSize.cx); //Deal with the case where there is a tab for an accelerator CString label=pItem->GetLabel(); int tabPos=label.Find('\t'); if(tabPos!=-1) { pDC->DrawText(label.Left(tabPos), -1, &rc, DT_LEFT | DT_VCENTER |DT_SINGLELINE); //Give the accelerator some room on the right rc.right-=ACCELERATOR_RIGHT + (m_WidestAccelerator - pItem->GetAcceleratorSize().cx); pDC->DrawText(label.Right(label.GetLength()-(tabPos+1)), -1, &rc, DT_RIGHT | DT_VCENTER |DT_SINGLELINE); } else { pDC->DrawText(label, -1, &rc, DT_LEFT | DT_VCENTER | DT_SINGLELINE |DT_EXPANDTABS); } pDC->SetBkMode(nOldBkMode); pDC->SetTextColor(rgbOldTxt); pDC->SelectObject(pOldFont); } // END OF FUNCTION CTreeMenu::DrawItem() /**************************************************************************** * * CTreeMenu::DrawImage * * PARAMETERS: * pDC - pointer to device context to draw on * rect - bounding rectangle to draw in * pItem - pointer to CTreeItem that contains the data * bIsSelected - is this item selected * * RETURNS: * width of the image, in pixels * * DESCRIPTION: * Protected helper function for drawing the bitmap image in a menu * item. We return the size of the painted image so the caller can * position the menu text after the image. * ****************************************************************************/ CSize CTreeMenu::DrawImage(CDC * pDC, const CRect & rect, CTreeItem * pItem, BOOL bIsSelected) { CSize sizeImg; sizeImg.cx = sizeImg.cy = 0; CBitmap * pImg = bIsSelected ? pItem->GetSelectedImage() : pItem->GetUnselectedImage(); if (pImg != NULL) { HPALETTE hPalette= WFE_GetUIPalette(m_pParent); HPALETTE hOldPalette = ::SelectPalette(pDC->m_hDC, hPalette, FALSE); // Get image dimensions BITMAP bmp; pImg->GetObject(sizeof(bmp), &bmp); sizeImg.cx = bmp.bmWidth; sizeImg.cy = bmp.bmHeight; // Create a scratch DC and select our bitmap into it. CDC * pBmpDC = new CDC; pBmpDC->CreateCompatibleDC(pDC); CBitmap * pOldBmp = pBmpDC->SelectObject(pImg); // Center the image horizontally and vertically CPoint ptDst(rect.left + (m_WidestImage - sizeImg.cx)/2, rect.top + (((rect.Height() - sizeImg.cy) + 1) / 2)); // Call the handy transparent blit function to paint the bitmap over // the background. if (pItem->GetIconType() == LOCAL_FILE) { HICON hIcon = pItem->GetLocalFileIcon(); DrawIconEx(pDC->m_hDC, ptDst.x, ptDst.y, hIcon, 0, 0, 0, NULL, DI_NORMAL); } else if (pItem->GetIconType() == ARBITRARY_URL) { CRDFImage* pImage = pItem->GetCustomIcon(); HDC hDC = pDC->m_hDC; int left = ptDst.x; int top = ptDst.y; int imageWidth = 16; int imageHeight = 16; COLORREF bkColor = bIsSelected ? GetSysColor(COLOR_HIGHLIGHT) : GetSysColor(COLOR_MENU); if (pImage && pImage->FrameLoaded()) { // Now we draw this bad boy. if (pImage->m_BadImage) { // display broken icon. HDC tempDC = ::CreateCompatibleDC(hDC); HBITMAP hOldBmp = (HBITMAP)::SelectObject(tempDC, CRDFImage::m_hBadImageBitmap); ::StretchBlt(hDC, left, top, imageWidth, imageHeight, tempDC, 0, 0, imageWidth, imageHeight, SRCCOPY); ::SelectObject(tempDC, hOldBmp); ::DeleteDC(tempDC); } else if (pImage->bits ) { // Center the image. long width = pImage->bmpInfo->bmiHeader.biWidth; long height = pImage->bmpInfo->bmiHeader.biHeight; int xoffset = (imageWidth-width)/2; int yoffset = (imageHeight-height)/2; if (xoffset < 0) xoffset = 0; if (yoffset < 0) yoffset = 0; if (width > imageWidth) width = imageWidth; if (height > imageHeight) height = imageHeight; HPALETTE hPal = WFE_GetUIPalette(NULL); HPALETTE hOldPal = ::SelectPalette(hDC, hPal, TRUE); ::RealizePalette(hDC); if (pImage->maskbits) { WFE_StretchDIBitsWithMask(hDC, TRUE, NULL, left+xoffset, top+xoffset, width, height, 0, 0, width, height, pImage->bits, pImage->bmpInfo, pImage->maskbits, FALSE, bkColor); } else { ::StretchDIBits(hDC, left+xoffset, top+xoffset, width, height, 0, 0, width, height, pImage->bits, pImage->bmpInfo, DIB_RGB_COLORS, SRCCOPY); } ::SelectPalette(hDC, hOldPal, TRUE); } } } else ::FEU_TransBlt(pBmpDC, pDC, CPoint(0, 0), ptDst, sizeImg.cx, sizeImg.cy, hPalette, PALETTERGB(255, 0, 255)); ::SelectPalette(pDC->m_hDC, hOldPalette, TRUE); // Cleanup pBmpDC->SelectObject(pOldBmp); pBmpDC->DeleteDC(); delete pBmpDC; } return(sizeImg); } // END OF FUNCTION CTreeMenu::DrawImage() void CTreeMenu::LoadComplete(HT_Resource r) { } /**************************************************************************** * * Class: CPopupTree * * DESCRIPTION: * This class represents a hierarchical popup menu object that can be * used for selecting from a list of sub-categorized items. * ****************************************************************************/ /**************************************************************************** * * CPopupTree::CPopupTree * * PARAMETERS: * pItems - list of items for filling the tree * * RETURNS: * N/A * * DESCRIPTION: * Constructor. * ****************************************************************************/ CPopupTree::CPopupTree(CTreeItemList * pItems) { m_pTree = pItems; } // END OF FUNCTION CPopupTree::CPopupTree() /**************************************************************************** * * CPopupTree::~CPopupTree * * PARAMETERS: * N/A * * RETURNS: * N/A * * DESCRIPTION: * Destructor. * ****************************************************************************/ CPopupTree::~CPopupTree() { // Time to take out the trash! We maintain a list of objects that were // dynamically allocated on the heap, but couldn't be conveniently // deleted. for (int i = 0; i < m_GarbageList.GetSize(); i++) { CObject * pObject = m_GarbageList.GetAt(i); if (pObject != NULL) { delete pObject; } } m_GarbageList.RemoveAll(); } // END OF FUNCTION CPopupTree::~CPopupTree() /**************************************************************************** * * CPopupTree::Activate * * PARAMETERS: * nX - horizontal position (screen coordinates) * nY - vertical position * pParent - pointer to parent window * * RETURNS: * TRUE if creation is successful * * DESCRIPTION: * This function is called to display the popup menu, after construction. * ****************************************************************************/ BOOL CPopupTree::Activate(int nX, int nY, CWnd * pParent) { CTreeMenu Menu; BOOL bRtn = Menu.Create(); // Now construct the menu from our tree BuildMenu(&Menu, m_pTree); if (bRtn) { bRtn = Menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, nX, nY, pParent); } return(bRtn); } // END OF FUNCTION CPopupTree::Activate() /**************************************************************************** * * CPopupTree::BuildMenu * * PARAMETERS: * pMenu - pointer to the menu to be constructed * pItems - list of item objects for building the menu * * RETURNS: * void * * DESCRIPTION: * This function is called to construct a custom menu from a list * of item objects. It is recursive and can be called for each node * that contains sub-items. * ****************************************************************************/ void CPopupTree::BuildMenu(CTreeMenu * pMenu, CTreeItemList * pItems) { for (int i = 0; i < pItems->GetSize(); i++) { CTreeItem * pItem = pItems->Get(i); ASSERT(pItem != NULL); if (pItem != NULL) { // See if this item has sub-items CTreeItemList * pSubItems = pItem->GetSubItems(); if (pSubItems->GetSize() > 0) { // It does, so create a new menu and call this function // recursively to construct it. CTreeMenu * pSubMenu = new CTreeMenu; // m_GarbageList.Add(pSubMenu); pSubMenu->Create(); BuildMenu(pSubMenu, pSubItems); pSubMenu->CalculateItemDimensions(); // Last but not least, add the new branch to the main menu BOOL bOk = pMenu->AddItem(pItem, 0, pSubMenu); ASSERT(bOk); } else { // Just add top-level item BOOL bOk = pMenu->AddItem(pItem); ASSERT(bOk); } } } pMenu->CalculateItemDimensions(); } // END OF FUNCTION CPopupTree::BuildMenu()