CMenu border color on MFC - mfc

I've a class that inherit from CMenu Owner draw menu
using this class the Menu appears correctly but, for example, when you open the menu FILE you will see the border and the separator of the standard menu color
How I can paint also this part of the desired color?
below an image, you can see the submenu of files with selected colors (green) and the standard windows menu gray on the borders/spacers

Using the menu example this is possible with these lines of code inside "AddSubMenus" function
MENUINFO MenuInfo = { 0 };
MenuInfo.cbSize = sizeof(MENUINFO);
GetMenuInfo(&MenuInfo);
MenuInfo.hbrBack = ::CreateSolidBrush(RGB(0, 0, 0));
MenuInfo.fMask = MIM_BACKGROUND | MIM_STYLE;
MenuInfo.dwStyle = MIM_APPLYTOSUBMENUS;
SetMenuInfo(&MenuInfo);
tmpmenu.SetMenuInfo(&MenuInfo);

Related

Popmenu item text color change when DarkGrey theme is applied

I have new to MFC, in my application when i click on icon drop down sub menu will popup,in that application DrakGrey theme is selected.
Problem : When sub menu popuped up text color is not visible (i wanted to change text color to white)
CToolBar * ToolBar = (CToolBar *) CWnd::FromHandle(hwndFrom );
CMenu menuobj;
menuobj.LoadMenu(dwMenuID);
CMenu* pPopup = menuobj.GetSubMenu(0);
After this adding menu items.
But not able to change the text color.
when Brush is updated total menu background changed ,but need to change only text color
MENUINFO menuInfo;
menuInfo.cbSize = sizeof( oInfo );
menuInfo.fMask = MIM_BACKGROUND | MIM_APPLYTOSUBMENUS;
menuInfo.hbrBack = m_brushBKG;
menu.SetMenuInfo( & menuInfo );

How to change the color of window border and title bar background programmatically when using DWM in win32?

I want to customize the window frame using DWM in win32 to get an appearance like VS2022 (draw menu on title bar) or Chrome (draw tabs on title bar), so I use the function DwmExtendFrameIntoClientArea with margin {0, 0, caption height, 0}. Unfortunately, it shows a white window border with 1-pixel width and white title bar area. I use the function DwmDefWindowProc to handle the system messages and show the system control buttons (min, max, close button). But I have no idea how to change the color of the window border and title bar background. If I paint in WM_PAINT, it may cover the system control buttons and looks weird. If I paint in WM_NCPAINT, the window shadow with WS_THICKFRAME style may disappear and need to draw which I feel is difficult to do.
Additionally, the 1-pixel width border may come from the following code:
if (message == WM_NCCALCSIZE) {
auto client_area_needs_calculating = static_cast<bool>(wparam);
if (client_area_needs_calculating) {
auto parameters = reinterpret_cast<NCCALCSIZE_PARAMS*>(lparam);
auto& requested_client_area = parameters->rgrc[0];
requested_client_area.right -= GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
requested_client_area.left += GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
requested_client_area.bottom -= GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
return 0;
}
}

Calculate font "size" in DIPs of a system font

I have few BS_OWNERDRAWN buttons and using Direct2D and Direct Write to draw them.
I also need to draw button text within button rectangle, for this I use IDWriteTextFormat which requires to specify "font size" in DIPs (device independent pixels).
I want font size in those buttons to be of same size as other non owner drawn common controls or same as system font that is present in window caption bar.
Following code is "chopped out" version to present my workaround which of course doesn't give expected results because I get LOGFONT structure of a font in caption bar which gives me the width of a font (single character) but not font size that the IDWriteTextFormat expects to specify font size in DIPs.
class CustomControl
{
protected:
/** Caption text format used to draw text */
CComPtr<IDWriteTextFormat> mpTextFormat;
/** Caption font size (button text size) */
float mFontSize;
};
// Calculate caption bar (default) font size of a top level window
void CustomControl::CalculateFontSize()
{
NONCLIENTMETRICSW metrics;
metrics.cbSize = sizeof(NONCLIENTMETRICSW);
SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0);
LOGFONTW font = metrics.lfCaptionFont;
mFontSize = static_cast<float>(font.lfHeight);
}
// Create text format that is of same font size as default system font
HRESULT CustomControl::CreateTextFormat()
{
HRESULT hr = S_OK;
if (!mpTextFormat)
{
CalculateFontSize();
hr = mpWriteFactory->CreateTextFormat(
L"Arial",
NULL,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
mFontSize, // <-- Specifies font size in DIP's..
L"en-us",
&mpTextFormat);
}
return hr;
}
Here is test program that shows the differences in font size between default system font in window caption and custom button text below.
I need help in figuring out how to correctly calculate font size for IDWriteTextFormat parameter to be of same size as text in other common controls that are not BS_OWNERDRAW or in this example default font in window caption.
EDIT:
I figured out issue is in my CalculateFontSize() I wrote mFontSize = static_cast<float>(font.lfHeight); but this is negative number so appending - sign gives the expected result:
mFontSize = static_cast<float>(-font.lfHeight);
Why negative? I'm not sure yet but this answer helped:
How to set font size using CreateFontA?
Now my question remains in that how should I update CalculateFontSize() so that it gets font size of common controls that are not BS_OWNERDRAW instead of a window caption bar font size?
I figured out to calculate font size of other common controls to be used for IDWriteTextFormat the formula is simple:
float CustomControl::CalculateFontSize()
{
const long units = GetDialogBaseUnits();
const DWORD height = HIWORD(units);
return static_cast<float>(height);
}
Only problem with this is if you use custom font for common controls, or if your dialog uses different font then you need to update your CalculateFontSize() to take these changes into account.
However for your TextFormat to be truly consistent with native common controls you also need to apply font weight (boldness), for example after you create TextLayout (by using your TextFormat):
std::size_t caption_len = 0;
StringCchLengthW(mCaption, STRSAFE_MAX_CCH, &caption_len);
DWRITE_TEXT_RANGE range = { 0u, caption_len };
mpTextLayout->SetFontSize(mFontSize, range);
mpTextLayout->SetFontWeight(DWRITE_FONT_WEIGHT::DWRITE_FONT_WEIGHT_BOLD, range);

CTabCtrl ItemAction & ItemState

I’ve created my own CXTabCtrl that extends CTabCtrl and override the DrawItem Function.
During the phase of rewriting the DrawItem Function, I wasn’t able to differentiate between this two states of CTabCtrl Item:
CTabCtrl item is selected and have focus.
CTabctrl item is selected but doesn’t have focus.
By focus I mean the Focus rectangle is not drawing. Here are two images that will help identify the two states:
Here’s the DrawItem current code, in which I can detect the selected states, but still Unable to detect the focus states.
Here’s a part of the DrawItem current code, in which I can detect the selected states, but still Unable to detect the focus states.
void CXtabCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
BOOL bFontSuccess = FALSE;
CFont* def_font = NULL;
CFont font_italic;
TC_ITEM tci;
CRect rect(lpDrawItemStruct->rcItem);
wchar_t szTabText[256];
wmemset(szTabText,_T('\0'),256);
RECT rectComplet;
GetClientRect(&rectComplet);
CBrush brtmp(ColorCategoryBackgroundTop);
int nbItem = GetItemCount();
tci.mask = TCIF_TEXT;
tci.pszText = szTabText;
tci.cchTextMax = sizeof(szTabText) -1;
GetItem(lpDrawItemStruct->itemID, &tci);
BOOL bSelect = (lpDrawItemStruct->itemState & ODS_SELECTED) &&
(lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE));
BOOL bfocus = (lpDrawItemStruct->itemState & ODS_FOCUS) &&
(lpDrawItemStruct->itemAction & (ODA_FOCUS | ODA_DRAWENTIRE));
if (bSelect)//Draw In a Specific Way
if (bFocus) //Draw In a Specific Way
}
So, I would be grateful if someone can describe the proper way to detect the two states of a CTabCtrl Item “Selected & Focused”, “Selected & But not focused”
For a standard tab control, the UI will not always draw the focus rectangle. To see the focus rectangle, the tab control must have WS_TABSTOP flag.
The focus rectangle will then be visible when user clicks the Tab key to go through the dialog's controls, or when Alt key is pressed and tab control has focus.
The focus rectangle should be drawn automatically for owner draw tab control when applicable. Make sure WS_TABSTOP is set for tab control (in dialog editor, go to tab control's properties and set "Tabstop = true")
BOOL focused = selected && (GetFocus() == this); will always be TRUE when user clicks on the tab control. ODS_NOFOCUSRECT will indicate if focus rectangle is not requested by the UI. See the example below.
Side note, sizeof(szTabText) returns the wrong value for wchar_t. Use _countof(szTabText) or sizeof(szTabText)/sizeof(*szTabText)
void CXtabCtrl::DrawItem(LPDRAWITEMSTRUCT di)
{
CDC* pDC = CDC::FromHandle(di->hDC);
TC_ITEM tci;
wchar_t text[256] = { 0 };
tci.mask = TCIF_TEXT;
tci.pszText = text;
tci.cchTextMax = _countof(text);
GetItem(di->itemID, &tci);
BOOL selected = di->itemState & ODS_SELECTED;
BOOL focused = selected && (GetFocus() == this);
//The UI may not be drawing focus rectangle, even if we click on the tab
if(di->itemState & ODS_NOFOCUSRECT)
focused = FALSE;
CString str;
if(selected) str += L"SEL ";//indicate selected
if(focused) str += L"FOC ";//indicate focused
CRect rect(di->rcItem);
pDC->TextOut(rect.left, rect.top, str);
}

Qt C++ window title bar is blocked

I'm very new to Qt and trying to create application, that includes main window, QDockWidget and a button.
Suppose my main window has 1280 x 720 resolution. Then I want to implement QDockWidget that pop up from the left side, width of dockWidth and height of 720 without windowTitleBar. The button has size of (buttonWidth, 720). At first its hidden, and only the button is present, when we click the button dock pops up, button changes position to the right edge of dock.
Here is my code:
window::window(unsigned int h, unsigned int v, QWidget *parent) {
this->setFixedSize(h, v);
ui.setupUi(this);
createDockWindow();
}
void window::createDockWindow() {
dock = new QDockWidget(this);
dock->setTitleBarWidget(new QMainWindow());
dock->setGeometry(QRect(this->rect().topLeft(),
QSize(dockWidth, this->height())));
dock->setFloating(true);
dock->hide();
path_button = new QPushButton(">", this);
path_button->setGeometry(QRect(this->rect().topLeft(),
QSize(buttonWidth, this->height())));
connect(path_button, SIGNAL (released()), this, SLOT (showDock()));
}
void rubrick::showDock() {
if(dock->isHidden()){
dock->show();
path_button->setGeometry(QRect(dock->rect().topRight(),
QSize(buttonWidth, this->height())));
} else {
dock->hide();
path_button->setGeometry(QRect(dock->rect().topLeft(),
QSize(buttonWidth, this->height())));
}
}
So button works perfectly, at first my app looks like that screenshot:
But when the dock shows, it blocks app window title bar, like that: screenshot
I figured, this->rect().topLeft() returns top left of screen, but doesn't take into consideration window Title Bar, I tried to get menuBar height, but it return 30, and I found out that if I move left top by (0, 45) with 0 being width and 45 being height, the dock would be perfectly in place.
What am I doing wrong and how to fix that problem?
The method you're probably looking for is QWidget::frameGeometry, which returns the geometry of the window with the frame included. The rect method returns only the internal area. If you look at QWidget::rect in Qt Assistant, you'll find a link to a "Window Geometry" description that explains all of these interactions reasonably well.