How can I bold a context menu item? - c++

I want to make the first item in a tray icon's context menu bold. It should be easy but I don't find my answer anywhere. Can someone please point me in the right direction? This is the code that I'm using to render the items:
void MenuItemWin::CreateNative(
LPMENUITEMINFO itemInfo, HMENU nativeParentMenu, bool registerNative)
{
ZeroMemory(itemInfo, sizeof(MENUITEMINFO));
itemInfo->cbSize = sizeof(MENUITEMINFO);
itemInfo->wID = ++UIWin::nextItemId;
itemInfo->dwItemData = (ULONG_PTR) this;
itemInfo->fMask = MIIM_ID | MIIM_FTYPE | MIIM_DATA;
HMENU nativeSubmenu = 0;
if (this->IsSeparator())
{
itemInfo->fType = MFT_SEPARATOR;
}
else
{
itemInfo->fMask = itemInfo->fMask | MIIM_STRING | MIIM_SUBMENU | MIIM_STATE;
itemInfo->fType = MFT_STRING;
itemInfo->fState = this->IsEnabled() ? MFS_ENABLED : MFS_DISABLED;
itemInfo->dwTypeData = (LPWSTR) this->wideOldLabel.c_str();
AutoPtr<MenuWin> wsubmenu = this->submenu.cast<MenuWin>();
if (!wsubmenu.isNull())
nativeSubmenu = wsubmenu->CreateNative(registerNative);
itemInfo->hSubMenu = nativeSubmenu;
if (this->IsCheck())
{
itemInfo->fState |= this->GetState() ? MFS_CHECKED : MFS_UNCHECKED;
}
else if (!this->iconPath.empty())
{
HBITMAP bitmap = UIWin::LoadImageAsBitmap(iconPath,
GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
if (bitmap)
{
itemInfo->fMask = itemInfo->fMask | MIIM_BITMAP;
itemInfo->hbmpItem = bitmap;
}
else
{
std::string error = Win32Utils::QuickFormatMessage(GetLastError());
Logger::Get("UI.MenuItem")->Error("Could not load icon (%s): %s",
iconPath.c_str(), error.c_str());
}
}
}
if (registerNative)
{
NativeItemBits* bits = new NativeItemBits;
bits->id = itemInfo->wID;
bits->parentMenu = nativeParentMenu;
bits->submenu = nativeSubmenu;
this->nativeItems.push_back(bits);
}
}

Related

DrawText Refresh Problem - Text Disappears

I'm using Objective Grid and wanted to have a grid cell control that can show an icon and text. So I took RogueWave's example (https://rwkbp.makekb.com/entry/466/) and modified it as below.
Initially the text renders correctly, but if I do anything in the grid that refreshes the relevant cell, the text disappears. If I update the whole grid, or even refresh the cell by dragging it off screen and back again, the text reappears - until it disappears again. Seems like a paint or InvalidateRect problem - but I can't figure out how to fix it. Any ideas?
Thanks!
//------------------------------------------------------------------------------
void CGXIconControl::Draw(CDC* pDC, CRect rect, ROWCOL nRow, ROWCOL nCol, const CGXStyle& style, const CGXStyle* pStandardStyle)
//------------------------------------------------------------------------------
{
BOOL b;
ASSERT(pDC != NULL && pDC->IsKindOf(RUNTIME_CLASS(CDC)));
// ASSERTION-> Invalid Device Context ->END
ASSERT(nRow <= Grid()->GetRowCount() && nCol <= Grid()->GetColCount());
// ASSERTION-> Cell coordinates out of range ->END
ASSERT_VALID(pDC);
DrawBackground(pDC, rect, style);
pDC->SetBkMode(TRANSPARENT);
if (rect.right <= rect.left || rect.Width() <= 1 || rect.Height() <= 1)
{
return;
}
CString str = style.GetIncludeValue() ? style.GetValue() : _T("");
CString sTxtBefore = _T("");
CString sTxtAfter = _T("");
int nHAlign = style.GetHorizontalAlignment();
int nVAlign = style.GetVerticalAlignment();
// Save these value to restore them when done drawing
COLORREF crOldTextColor = pDC->GetTextColor();
COLORREF crOldBkColor = pDC->GetBkColor();
if (!style.GetEnabled())
{
pDC->SetTextColor(::GetSysColor(COLOR_GRAYTEXT));
}
CBrush Brush;
Brush.CreateSolidBrush(style.GetEnabled() ? ::GetSysColor(COLOR_WINDOWTEXT) : ::GetSysColor(COLOR_GRAYTEXT));
LOGBRUSH lBrush = { 0 };
Brush.GetLogBrush(&lBrush);
CBrush* pOldBrush = (CBrush*)pDC->SelectStockObject(NULL_BRUSH);
CPen linePen;
linePen.CreatePen(PS_SOLID, 1, &lBrush);
CPen* pOldPen = pDC->SelectObject(&linePen);
// Set font bold if necessary
CFont* pCurfont = pDC->GetCurrentFont();
LOGFONT lf;
CFont font;
if (pCurfont)
{
pCurfont->GetLogFont(&lf);
}
if (style.GetFont().GetBold())
{
lf.lfWeight = FW_BOLD;
}
font.CreateFontIndirect(&lf);
CFont* pOldFont = pDC->SelectObject(&font);
int nIcoStart = str.Find(_T("#ICO"));
if (nIcoStart == -1)
{
// We didn't find an icon indicator, so just draw the text
pDC->DrawText(str, rect, DT_SINGLELINE|nHAlign|nVAlign);
}
else
{
sTxtBefore = str.Left(nIcoStart);
CSize szBefore = pDC->GetTextExtent(sTxtBefore);
int nIconEnd = str.Find(_T(")"), nIcoStart);
CString strIDResource = str.Mid(nIcoStart + 5, nIconEnd - (nIcoStart + 5));
UINT nIDResource = _ttoi(strIDResource);
// Load the highest bit-depth available
HICON hIcon = NULL;
hIcon = LoadResourceIcon(nIDResource, m_nIconSize, m_nIconSize, 32);
hIcon == NULL ? LoadResourceIcon(nIDResource, m_nIconSize, m_nIconSize, 24) : NULL;
hIcon == NULL ? LoadResourceIcon(nIDResource, m_nIconSize, m_nIconSize, 16) : NULL;
hIcon == NULL ? LoadResourceIcon(nIDResource, m_nIconSize, m_nIconSize, 8) : NULL;
sTxtAfter = str.Right(str.GetLength() - nIconEnd - 1);
CSize szAfter = pDC->GetTextExtent(sTxtAfter);
CRect rectCell = CGXControl::GetCellRect(nRow, nCol, rect, &style);
CRect rectBefore = rectCell;
CRect rectAfter = rectCell;
int nTotalWidth = szBefore.cx + m_nIconSize + szAfter.cx;
// Calculate positions
int nTop, nLeft;
switch (nHAlign)
{
case DT_LEFT:
{
rectBefore.right = rectBefore.left + szBefore.cx;
nLeft = rectBefore.right;
rectAfter.left = nLeft + m_nIconSize;
rectAfter.right = rectAfter.left + szAfter.cx;
} break;
case DT_CENTER:
{
rectBefore.left = (rectCell.right - rectCell.Width() / 2) - nTotalWidth / 2;
rectBefore.right = rectBefore.left + szBefore.cx;
nLeft = rectBefore.right;
rectAfter.left = nLeft + m_nIconSize;
rectAfter.right = rectAfter.left + szAfter.cx;
} break;
case DT_RIGHT:
{
// Work from the right
rectAfter.right = rectCell.right;
rectAfter.left = rectAfter.right - szAfter.cx;
nLeft = rectAfter.left - m_nIconSize;
rectBefore.right = nLeft;
rectBefore.left = rectBefore.right - szBefore.cx;
} break;
}
switch (nVAlign)
{
case DT_TOP:
nTop = rectCell.top;
break;
case DT_VCENTER:
nTop = rectCell.top + (rectCell.Height() / 2 - m_nIconSize / 2);
break;
case DT_BOTTOM:
nTop = rectCell.bottom - m_nIconSize;
break;
}
if (!sTxtBefore.IsEmpty())
{
pDC->DrawText(sTxtBefore, rectBefore, DT_SINGLELINE|nHAlign|nVAlign);
}
b = ::DrawIconEx(pDC->m_hDC, nLeft, nTop, hIcon, m_nIconSize, m_nIconSize, 0, NULL, DI_NORMAL);
b = ::DestroyIcon(hIcon);
if (!sTxtAfter.IsEmpty())
{
pDC->DrawText(sTxtAfter, rectAfter, DT_SINGLELINE|nHAlign|nVAlign);
}
}
// Reset original values
pDC->SetTextColor(crOldTextColor);
pDC->SetBkColor(crOldBkColor);
pDC->SelectObject(pOldBrush);
pDC->SelectObject(pOldPen);
pDC->SelectObject(pOldFont);
// Child Controls: spin-buttons, hotspot, combobox btn, ...
CGXControl::Draw(pDC, rect, nRow, nCol, style, pStandardStyle);
}

TreeView add Shell Icons

I already created treeview where I can add some items. Basicly I want to tree-view all directories and files with icons associated to them.
So I have these functions:
Adding items to treeview
HTREEITEM AddItemToTree(HWND hwndTree, char *text, int nLevel)
{
TVINSERTSTRUCT tvins;
static HTREEITEM hPrev = (HTREEITEM)TVI_FIRST;
static HTREEITEM hRootItem = NULL;
static HTREEITEM hPrevLev2Item = NULL;
AddIconToTree(hwndTree, text); //////////// THIS IS THE FUNCTION BELOW...
tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIS_STATEIMAGEMASK;
tvi.iImage = 0;
tvi.iSelectedImage = 0;
tvi.pszText = GetFileNameFromPath(text);
tvins.hInsertAfter = hPrev;
tvins.item = tvi;
if(nLevel == 1)
{
tvins.hParent = TVI_ROOT;
}
else if(nLevel == 2)
{
tvins.hParent = hRootItem;
}
else
{
TVITEM tviSetup;
tviSetup.hItem = hPrev;
tviSetup.mask = TVIF_PARAM;
TVITEM * tviLocal = &tviSetup;
TreeView_GetItem(hwndTree, tviLocal);
if(nLevel > tviLocal->lParam)
{
tvins.hParent = hPrev;
}
else
{
HTREEITEM hPrevLocal = TreeView_GetParent(hwndTree, hPrev);
tviLocal->hItem = hPrevLocal;
TreeView_GetItem(hwndTree, tviLocal);
for(int i = nLevel; i <= tviLocal->lParam;)
{
HTREEITEM hPrevLocalTemp = TreeView_GetParent(hwndTree, hPrevLocal);
hPrevLocal = hPrevLocalTemp;
tviLocal->hItem = hPrevLocal;
TreeView_GetItem(hwndTree, tviLocal);
}
tviLocal->mask = TVIF_TEXT;
TreeView_GetItem(hwndTree, tviLocal);
tvins.hParent = hPrevLocal;
}
}
hPrev = (HTREEITEM)SendMessage(hwndTree, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
if(hPrev == 0)
{
return false;
}
if(nLevel == 1)
{
hRootItem = hPrev;
}
return hPrev;
}
ADDING ICONS TO TREEVIEW:
int AddIconToTree(HWND hwndTree, char *strPath)
{
SHFILEINFO sfi;
memset(&sfi, 0, sizeof(sfi));
SHGetFileInfo(strPath, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | SHGFI_SMALLICON);
int index = sfi.iIcon;
ICONINFO iconinfo;
GetIconInfo(sfi.hIcon, &iconinfo);
HBITMAP hBitmap = iconinfo.hbmColor;
DestroyIcon(sfi.hIcon);
himg = ImageList_Create(16, 16, ILC_COLOR32, 1, 1);
int iImageList = ImageList_Add(himg, hBitmap, NULL);
DeleteObject(hBitmap);
//TreeView_SetImageList(hwndTree, himg, TVSIL_NORMAL);
SendMessage(hwndTree, TVM_SETIMAGELIST, (WPARAM)TVSIL_NORMAL, (LPARAM)(HIMAGELIST)himg);
MessageBox(hwnd, strPath, "Path:", MB_OK); /* Because of this msgbox I found out what is
really happening, because without it everything I have seen when I run the program was
treeview with icon of the last file, which was folder...So blank icon.*/
return index;
}
My main problem is, that when I'm setting some icon, it is set not only for the one item as I'm expecting, but on all items in treeview. So basicly every item's icon is overwritten by new item's icon. By the way I know that if I want to get icon of folder, I need to use FILE_ATTRIBUTE_DIRECTORY...
So that's it.
Any help would be greatly appriciated!
Thank You in advance :-)
In your AddIconToTree function you're creating a brand new image list every time, which will only ever have one icon in it. You need to maintain the same image list and add additional icons to it rather than re-creating it for every item.
Alternatively, you can get a handle to the shell imagelist with the SHGetImageList function and then assign it to the tree directly. If you don't need to add any of your own images to the tree's image list this is a much easier way of displaying system icons for files and folders as the shell imagelist handles all that for you.
// To initialise the tree's image list - do this one time only
HIMAGELIST himg;
if (SUCCEEDED(SHGetImageList(SHIL_SMALL, IID_IImageList, reinterpret_cast<void**>(&himg))))
SendMessage(hwndTree, TVM_SETIMAGELIST, (WPARAM)TVSIL_NORMAL, (LPARAM)himg);
Then your AddIconToTree function simply becomes:
int AddIconToTree(HWND hwndTree, char *strPath)
{
SHFILEINFO sfi;
memset(&sfi, 0, sizeof(sfi));
// SHGFI_SYSICONINDEX will return the icon's index within the shell image list
SHGetFileInfo(strPath, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi),
SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES);
return sfi.iIcon;
}
And when you actually add items to the list, make sure you assign the index to the item:
tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIS_STATEIMAGEMASK;
tvi.iImage = tvi.iSelectedImage = AddIconToTree(hwndTree, text);

Can't insert a item of list control

I'm trying to insert a item of list control when an add button is clicked.
But an add button is clicked, it does not insert a item.
also I changed View property of list control from icon to report.
Does following code have a problem?
BOOL CMFCApplication7Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
SetIcon(m_hIcon, TRUE);
SetIcon(m_hIcon, FALSE);
// Here is insert columns.
TCHAR *szText[2] = { _T("NAME"), _T("E-MAIL") };
int nWid[2] = { 65, 180 };
LV_COLUMN lCol;
lCol.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
lCol.fmt = LVCFMT_LEFT;
for (int i = 0; i < 2;i++)
{
lCol.pszText = szText[i];
lCol.iSubItem = i;
lCol.cx = nWid[i];
m_ListC.InsertColumn(i, &lCol);
}
return TRUE;
}
// Here is insert item code.
void CMFCApplication7Dlg::OnBnClickedButtAdd()
{
TCHAR szText[50] = _T("");
int nIndex = 0;
UpdateData(TRUE);
LVITEM litem;
litem.mask = LVIF_TEXT;
litem.iItem = nIndex;
litem.iSubItem = 0;
swprintf_s(szText, sizeof(szText), _T("%s"), m_strName);
litem.pszText = (LPWSTR)szText;
m_ListC.InsertItem(&litem);
litem.iSubItem = 1;
swprintf_s(szText, sizeof(szText), _T("%s"), m_strMail);
litem.pszText = (LPWSTR)szText;
m_ListC.SetItem(&litem);
m_strName = _T("");
m_strMail = _T("");
nIndex++;
UpdateData(FALSE);
}
You set information LVITEM that is not covered by the mask. Also the iSubItem member is not used in report mode when you insert a normal column.
User the member functions of the m_listC InsertColumn, InsertItem and SetItemText instead of the struct Version. It is less error prone.
Tipp: Use ASSERT/VERIFY to check if the things you are doing work... You have no error checking in your code.

Set GDI page settings for printing C++

I am having trouble setting the "default" page size for my document. I am using Visual C++ on Windows, with GDI calls (required for backward-compatibility).
So far my basic approach is to get a default DEVMODE, set the properties on it that I want, and then prompt the user if he wants to change it. But it seems to make no difference on the page size. It works on Orientation.
What am I doing wrong?
HDC GetPrinterDC () {
// Initialize device
PRINTDLG pd = {0};
pd.lStructSize = sizeof( pd );
pd.Flags = PD_RETURNDEFAULT;
PrintDlg(&pd);
// If device initialization failed, abort
if (pd.hDevMode == NULL) return NULL;
// Get the actual memory pointer
PDEVMODE dm = (PDEVMODE)GlobalLock(pd.hDevMode);
if (dm) {
// Set any properties that are specific for our document
if (dm->dmFields & DM_ORIENTATION)
dm->dmOrientation = DMORIENT_LANDSCAPE;
if (dm->dmFields & DM_PAPERSIZE)
dm->dmPaperSize = 0;
if (dm->dmFields & DM_PAPERLENGTH)
dm->dmPaperLength = 3302; // 13in
if (dm->dmFields & DM_PAPERWIDTH)
dm->dmPaperWidth = 4572; // 18in
GlobalUnlock(pd.hDevMode);
}
// Initialize a PRINTDLG structure.
pd.hwndOwner = GetForegroundWindow();
pd.Flags = PD_RETURNDC | PD_HIDEPRINTTOFILE | PD_DISABLEPRINTTOFILE | PD_NOPAGENUMS | PD_NOSELECTION | PD_USEDEVMODECOPIESANDCOLLATE ;
// Retrieve the printer DC
HDC hdc = NULL;
if (PrintDlg(&pd)) hdc = pd.hDC;
// Free the resources allocated
if (pd.hDevMode != NULL) GlobalFree(pd.hDevMode);
if (pd.hDevNames != NULL) GlobalFree(pd.hDevNames);
return hdc;
}
Apparently you can specify dmFields in the DEVMODE struct to be anything you want.
The code should look like this:
PDEVMODE dm = (PDEVMODE)GlobalLock(pd.hDevMode);
if (dm) {
// Set any properties that are specific for our document
dm->dmFields = dm->dmFields | DM_ORIENTATION | DM_PAPERSIZE
| DM_PAPERLENGTH | DM_PAPERWIDTH;
dm->dmOrientation = DMORIENT_LANDSCAPE;
dm->dmPaperSize = 0;
dm->dmPaperLength = 3302; // 13in
dm->dmPaperWidth = 4572; // 18in
GlobalUnlock(pd.hDevMode);
}

Trying to create my own Toolbar inside Mainframe class VS 6.0

I am having issues with creating my own Toolbar inside the Mainframe. I have bitmaps of buttons which I want to use for my own Toolbar but the problem is that the Toolbar displays inside the View of my SDI application. Here is a pic of the incorrectly displayed Toolbar.
http://www.flickr.com/photos/14402427#N02/3409050475/
Here is the code inside the OnCreate function of the Mainframe class : I also have a
// CToolBarCtrl m_wndToolBar; declared inside the MainFrame.h class.
if(m_wndToolBar.Create(WS_CHILD | TBSTYLE_FLAT | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC
,CRect(0,0,250,50),this,0))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
TBBUTTON tbbutton[3] = {0};
CSize button_size(90,90);
CSize bitmap_size(80,80);
//m_wndToolBar.AddStrings("String 1\0String 2\0String 3\0");
tbbutton[0].iBitmap = 0;
tbbutton[0].idCommand = ID_CONNECT;
tbbutton[0].fsState = TBSTATE_ENABLED;
tbbutton[0].fsStyle = TBSTYLE_BUTTON;
tbbutton[0].dwData = 0;
tbbutton[0].iString = 0;
tbbutton[1].iBitmap = 1;
tbbutton[1].idCommand = ID_DISCONNECT;
tbbutton[1].fsState = TBSTATE_ENABLED;
tbbutton[1].fsStyle = TBSTYLE_BUTTON;
tbbutton[1].dwData = 0;
tbbutton[1].iString = 1;
tbbutton[2].iBitmap = 2;
tbbutton[2].idCommand = ID_STOP;
tbbutton[2].fsState = TBSTATE_ENABLED;
tbbutton[2].fsStyle = TBSTYLE_BUTTON ;
tbbutton[2].dwData = 0;
tbbutton[2].iString = 2;
m_wndToolBar.SetButtonSize(button_size);
m_wndToolBar.SetBitmapSize( bitmap_size);
m_wndToolBar.AddButtons(3,tbbutton);
m_wndToolBar.AddBitmap(1,IDB_BITMAP1);
m_wndToolBar.AddBitmap(1,IDB_BITMAP2);
m_wndToolBar.AddBitmap(1,IDB_BITMAP3);
return TRUE;
Add a call to DockControlBar(&m_wndToolBar) just before the return.
From your image it seems that it is not painted or not painted correctly, did you try adding bitmaps first and then adding buttons? or can you call AutoSize on the m_wndToolbarBar.?