Add "Show All Character" context menu on toolbar button

Fix #14832, close #15235
This commit is contained in:
ozone10 2024-06-02 10:39:12 +02:00 committed by Don Ho
parent 7a401cface
commit e7e88a380a
4 changed files with 238 additions and 14 deletions

View File

@ -99,11 +99,21 @@ ToolBarButtonUnit toolBarIcons[] = {
{IDM_VIEW_WRAP, IDI_VIEW_WRAP_ICON, IDI_VIEW_WRAP_ICON, IDI_VIEW_WRAP_ICON2, IDI_VIEW_WRAP_ICON2, IDI_VIEW_WRAP_ICON_DM, IDI_VIEW_WRAP_ICON_DM, IDI_VIEW_WRAP_ICON_DM2, IDI_VIEW_WRAP_ICON_DM2, IDR_WRAP},
{IDM_VIEW_ALL_CHARACTERS, IDI_VIEW_ALL_CHAR_ICON, IDI_VIEW_ALL_CHAR_ICON, IDI_VIEW_ALL_CHAR_ICON2, IDI_VIEW_ALL_CHAR_ICON2, IDI_VIEW_ALL_CHAR_ICON_DM, IDI_VIEW_ALL_CHAR_ICON_DM, IDI_VIEW_ALL_CHAR_ICON_DM2, IDI_VIEW_ALL_CHAR_ICON_DM2, IDR_INVISIBLECHAR},
{IDM_VIEW_INDENT_GUIDE, IDI_VIEW_INDENT_ICON, IDI_VIEW_INDENT_ICON, IDI_VIEW_INDENT_ICON2, IDI_VIEW_INDENT_ICON2, IDI_VIEW_INDENT_ICON_DM, IDI_VIEW_INDENT_ICON_DM, IDI_VIEW_INDENT_ICON_DM2, IDI_VIEW_INDENT_ICON_DM2, IDR_INDENTGUIDE},
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//
{0, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON},
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//
{IDM_LANG_USER_DLG, IDI_VIEW_UD_DLG_ICON, IDI_VIEW_UD_DLG_ICON, IDI_VIEW_UD_DLG_ICON2, IDI_VIEW_UD_DLG_ICON2, IDI_VIEW_UD_DLG_ICON_DM, IDI_VIEW_UD_DLG_ICON_DM, IDI_VIEW_UD_DLG_ICON_DM2, IDI_VIEW_UD_DLG_ICON_DM2, IDR_SHOWPANNEL},
{IDM_VIEW_DOC_MAP, IDI_VIEW_DOC_MAP_ICON, IDI_VIEW_DOC_MAP_ICON, IDI_VIEW_DOC_MAP_ICON2, IDI_VIEW_DOC_MAP_ICON2, IDI_VIEW_DOC_MAP_ICON_DM, IDI_VIEW_DOC_MAP_ICON_DM, IDI_VIEW_DOC_MAP_ICON_DM2, IDI_VIEW_DOC_MAP_ICON_DM2, IDR_DOCMAP},
{IDM_VIEW_DOCLIST, IDI_VIEW_DOCLIST_ICON, IDI_VIEW_DOCLIST_ICON, IDI_VIEW_DOCLIST_ICON2, IDI_VIEW_DOCLIST_ICON2, IDI_VIEW_DOCLIST_ICON_DM, IDI_VIEW_DOCLIST_ICON_DM, IDI_VIEW_DOCLIST_ICON_DM2, IDI_VIEW_DOCLIST_ICON_DM2, IDR_DOCLIST},
{IDM_VIEW_FUNC_LIST, IDI_VIEW_FUNCLIST_ICON, IDI_VIEW_FUNCLIST_ICON, IDI_VIEW_FUNCLIST_ICON2, IDI_VIEW_FUNCLIST_ICON2, IDI_VIEW_FUNCLIST_ICON_DM, IDI_VIEW_FUNCLIST_ICON_DM, IDI_VIEW_FUNCLIST_ICON_DM2, IDI_VIEW_FUNCLIST_ICON_DM2, IDR_FUNC_LIST},
{IDM_VIEW_FILEBROWSER, IDI_VIEW_FILEBROWSER_ICON, IDI_VIEW_FILEBROWSER_ICON, IDI_VIEW_FILEBROWSER_ICON2, IDI_VIEW_FILEBROWSER_ICON2, IDI_VIEW_FILEBROWSER_ICON_DM, IDI_VIEW_FILEBROWSER_ICON_DM, IDI_VIEW_FILEBROWSER_ICON_DM2, IDI_VIEW_FILEBROWSER_ICON_DM2, IDR_FILEBROWSER},
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//
{0, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON, IDI_SEPARATOR_ICON},
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//
{IDM_VIEW_MONITORING, IDI_VIEW_MONITORING_ICON, IDI_VIEW_MONITORING_DIS_ICON, IDI_VIEW_MONITORING_ICON2, IDI_VIEW_MONITORING_DIS_ICON2, IDI_VIEW_MONITORING_ICON_DM, IDI_VIEW_MONITORING_DIS_ICON_DM, IDI_VIEW_MONITORING_ICON_DM2, IDI_VIEW_MONITORING_DIS_ICON_DM2, IDR_FILEMONITORING},
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//
@ -8965,3 +8975,105 @@ void Notepad_plus::changedHistoryGoTo(int idGoTo)
::MessageBeep(MB_ICONEXCLAMATION);
}
}
HMENU Notepad_plus::createMenuFromMenu(HMENU hSourceMenu, std::vector<int>& commandIds)
{
HMENU hNewMenu = ::CreatePopupMenu();
for (const auto& cmdID : commandIds)
{
if (cmdID == 0)
{
::AppendMenu(hNewMenu, MF_SEPARATOR, 0, nullptr);
}
else
{
MENUITEMINFO mii{};
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_STRING | MIIM_STATE;
mii.dwTypeData = nullptr;
if (::GetMenuItemInfo(hSourceMenu, cmdID, FALSE, &mii) == TRUE)
{
++mii.cch;
wchar_t* szString = new wchar_t[mii.cch];
mii.dwTypeData = szString;
if (::GetMenuItemInfo(hSourceMenu, cmdID, FALSE, &mii) == TRUE)
{
::AppendMenu(hNewMenu, MF_STRING | mii.fState, cmdID, mii.dwTypeData);
delete[] szString;
}
else
{
delete[] szString;
::DestroyMenu(hNewMenu);
return nullptr;
}
}
else
{
::DestroyMenu(hNewMenu);
return nullptr;
}
}
}
return hNewMenu;
}
BOOL Notepad_plus::notifyTBShowMenu(LPNMTOOLBARW lpnmtb, const char* menuPosId)
{
RECT rcItem{};
::SendMessage(lpnmtb->hdr.hwndFrom, TB_GETRECT, static_cast<WPARAM>(lpnmtb->iItem), reinterpret_cast<LPARAM>(&rcItem));
::MapWindowPoints(lpnmtb->hdr.hwndFrom, HWND_DESKTOP, reinterpret_cast<LPPOINT>(&rcItem), 2);
const MenuPosition& menuPos = getMenuPosition(menuPosId);
HMENU hSubMenuView = ::GetSubMenu(_mainMenuHandle, menuPos._x);
if (hSubMenuView != nullptr)
{
HMENU hPopupMenu = ::GetSubMenu(hSubMenuView, menuPos._y);
if (hPopupMenu != nullptr)
{
TPMPARAMS tpm{};
tpm.cbSize = sizeof(TPMPARAMS);
tpm.rcExclude = rcItem;
const UINT flags = _nativeLangSpeaker.isRTL() ? (TPM_RIGHTALIGN | TPM_RIGHTBUTTON | TPM_LAYOUTRTL) : (TPM_LEFTALIGN | TPM_LEFTBUTTON);
::TrackPopupMenuEx(hPopupMenu,
flags | TPM_VERTICAL,
rcItem.left, rcItem.bottom, _pPublicInterface->getHSelf(), &tpm);
return TRUE;
}
}
return FALSE;
}
BOOL Notepad_plus::notifyTBShowMenu(LPNMTOOLBARW lpnmtb, const char* menuPosId, std::vector<int> cmdIDs)
{
if (cmdIDs.empty())
return notifyTBShowMenu(lpnmtb, menuPosId);
RECT rcItem{};
::SendMessage(lpnmtb->hdr.hwndFrom, TB_GETRECT, static_cast<WPARAM>(lpnmtb->iItem), reinterpret_cast<LPARAM>(&rcItem));
::MapWindowPoints(lpnmtb->hdr.hwndFrom, HWND_DESKTOP, reinterpret_cast<LPPOINT>(&rcItem), 2);
HMENU hPopupMenu = createMenuFromMenu(_mainMenuHandle, cmdIDs);
if (hPopupMenu != nullptr)
{
TPMPARAMS tpm{};
tpm.cbSize = sizeof(TPMPARAMS);
tpm.rcExclude = rcItem;
const UINT flags = _nativeLangSpeaker.isRTL() ? (TPM_RIGHTALIGN | TPM_RIGHTBUTTON | TPM_LAYOUTRTL) : (TPM_LEFTALIGN | TPM_LEFTBUTTON);
::TrackPopupMenuEx(hPopupMenu,
flags | TPM_VERTICAL,
rcItem.left, rcItem.bottom, _pPublicInterface->getHSelf(), &tpm);
::DestroyMenu(hPopupMenu);
return TRUE;
}
return FALSE;
}

View File

@ -653,4 +653,8 @@ private:
void clearChangesHistory();
void changedHistoryGoTo(int idGoTo);
HMENU createMenuFromMenu(HMENU hSourceMenu, std::vector<int>& commandIds);
BOOL notifyTBShowMenu(LPNMTOOLBARW lpnmtb, const char* menuPosId);
BOOL notifyTBShowMenu(LPNMTOOLBARW lpnmtb, const char* menuPosId, std::vector<int> cmdIDs);
};

View File

@ -1,4 +1,4 @@
// This file is part of Notepad++ project
// This file is part of Notepad++ project
// Copyright (C)2021 Don HO <don.h@free.fr>
// This program is free software: you can redistribute it and/or modify
@ -2013,11 +2013,34 @@ LRESULT Notepad_plus::process(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
nmtbcd->nStringBkMode = TRANSPARENT;
nmtbcd->nHLStringBkMode = TRANSPARENT;
RECT rcItem{ nmtbcd->nmcd.rc };
RECT rcDrop{};
TBBUTTONINFO tbi{};
tbi.cbSize = sizeof(TBBUTTONINFO);
tbi.dwMask = TBIF_STYLE;
::SendMessage(lpnmhdr->hwndFrom, TB_GETBUTTONINFO, nmtbcd->nmcd.dwItemSpec, reinterpret_cast<LPARAM>(&tbi));
const bool isDropDown = (tbi.fsStyle & BTNS_DROPDOWN) == BTNS_DROPDOWN;
if (isDropDown)
{
WPARAM idx = ::SendMessage(lpnmhdr->hwndFrom, TB_COMMANDTOINDEX, nmtbcd->nmcd.dwItemSpec, 0);
::SendMessage(lpnmhdr->hwndFrom, TB_GETITEMDROPDOWNRECT, idx, reinterpret_cast<LPARAM>(&rcDrop));
rcItem.right = rcDrop.left;
}
if ((nmtbcd->nmcd.uItemState & CDIS_HOT) == CDIS_HOT)
{
auto holdBrush = ::SelectObject(nmtbcd->nmcd.hdc, NppDarkMode::getHotBackgroundBrush());
auto holdPen = ::SelectObject(nmtbcd->nmcd.hdc, NppDarkMode::getHotEdgePen());
::RoundRect(nmtbcd->nmcd.hdc, nmtbcd->nmcd.rc.left, nmtbcd->nmcd.rc.top, nmtbcd->nmcd.rc.right, nmtbcd->nmcd.rc.bottom, roundCornerValue, roundCornerValue);
::RoundRect(nmtbcd->nmcd.hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom, roundCornerValue, roundCornerValue);
if (isDropDown)
{
::RoundRect(nmtbcd->nmcd.hdc, rcDrop.left, rcDrop.top, rcDrop.right, rcDrop.bottom, roundCornerValue, roundCornerValue);
}
::SelectObject(nmtbcd->nmcd.hdc, holdBrush);
::SelectObject(nmtbcd->nmcd.hdc, holdPen);
@ -2027,7 +2050,14 @@ LRESULT Notepad_plus::process(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
{
auto holdBrush = ::SelectObject(nmtbcd->nmcd.hdc, NppDarkMode::getSofterBackgroundBrush());
auto holdPen = ::SelectObject(nmtbcd->nmcd.hdc, NppDarkMode::getEdgePen());
::RoundRect(nmtbcd->nmcd.hdc, nmtbcd->nmcd.rc.left, nmtbcd->nmcd.rc.top, nmtbcd->nmcd.rc.right, nmtbcd->nmcd.rc.bottom, roundCornerValue, roundCornerValue);
::RoundRect(nmtbcd->nmcd.hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom, roundCornerValue, roundCornerValue);
if (isDropDown)
{
::RoundRect(nmtbcd->nmcd.hdc, rcDrop.left, rcDrop.top, rcDrop.right, rcDrop.bottom, roundCornerValue, roundCornerValue);
}
::SelectObject(nmtbcd->nmcd.hdc, holdBrush);
::SelectObject(nmtbcd->nmcd.hdc, holdPen);
@ -2040,9 +2070,40 @@ LRESULT Notepad_plus::process(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
lr |= TBCDRF_NOBACKGROUND;
}
if (isDropDown)
{
lr |= CDRF_NOTIFYPOSTPAINT;
}
return lr;
}
case CDDS_ITEMPOSTPAINT:
{
const UINT dpi = DPIManagerV2::getDpiForWindow(hwnd);
LOGFONT lf{ DPIManagerV2::getDefaultGUIFontForDpi(dpi) };
HFONT hFont = CreateFontIndirect(&lf);
auto holdFont = static_cast<HFONT>(::SelectObject(nmtbcd->nmcd.hdc, hFont));
RECT rcArrow{};
WPARAM idx = ::SendMessage(lpnmhdr->hwndFrom, TB_COMMANDTOINDEX, nmtbcd->nmcd.dwItemSpec, 0);
::SendMessage(lpnmhdr->hwndFrom, TB_GETITEMDROPDOWNRECT, idx, reinterpret_cast<LPARAM>(&rcArrow));
rcArrow.left += DPIManagerV2::scale(1, dpi);
rcArrow.bottom -= DPIManagerV2::scale(3, dpi);
COLORREF clrArrow = NppDarkMode::getTextColor();
::SetBkMode(nmtbcd->nmcd.hdc, TRANSPARENT);
::SetTextColor(nmtbcd->nmcd.hdc, clrArrow);
::DrawText(nmtbcd->nmcd.hdc, L"", -1, &rcArrow, DT_NOPREFIX | DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP);
::SelectObject(nmtbcd->nmcd.hdc, holdFont);
::DeleteObject(hFont);
return CDRF_DODEFAULT;
}
default:
break;
}
@ -2050,6 +2111,40 @@ LRESULT Notepad_plus::process(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
return CDRF_DODEFAULT;
}
case TBN_DROPDOWN:
{
auto lpnmtb = reinterpret_cast<LPNMTOOLBARW>(lParam);
switch (lpnmtb->iItem)
{
case IDM_VIEW_ALL_CHARACTERS:
{
auto cmdIDs = { IDM_VIEW_TAB_SPACE, IDM_VIEW_EOL, IDM_VIEW_NPC, IDM_VIEW_NPC_CCUNIEOL, 0, IDM_VIEW_ALL_CHARACTERS };
notifyTBShowMenu(lpnmtb, "view-showSymbol", cmdIDs);
return TBDDRET_DEFAULT;
}
default:
break;
}
return TBDDRET_NODEFAULT;
}
case NM_RCLICK:
{
auto lpnmtb = reinterpret_cast<LPNMTOOLBARW>(lParam);
switch (lpnmtb->iItem)
{
case IDM_VIEW_ALL_CHARACTERS:
{
return notifyTBShowMenu(lpnmtb, "view-showSymbol");
}
default:
break;
}
return FALSE;
}
default:
return FALSE;
}

View File

@ -151,14 +151,27 @@ bool ToolBar::init( HINSTANCE hInst, HWND hPere, toolBarStatusType type, ToolBar
for (; i < _nbButtons && i < _nbTotalButtons; ++i)
{
cmd = buttonUnitArray[i]._cmdID;
if (cmd != 0)
switch (cmd)
{
case 0:
{
style = BTNS_SEP;
break;
}
case IDM_VIEW_ALL_CHARACTERS:
{
++bmpIndex;
style = BTNS_DROPDOWN;
break;
}
default:
{
++bmpIndex;
style = BTNS_BUTTON;
break;
}
else
{
style = BTNS_SEP;
}
_pTBB[i].iBitmap = (cmd != 0 ? bmpIndex : 0);
@ -169,7 +182,7 @@ bool ToolBar::init( HINSTANCE hInst, HWND hPere, toolBarStatusType type, ToolBar
_pTBB[i].iString = 0;
}
if (_nbDynButtons > 0)
if (_nbDynButtons > 0 && i < _nbTotalButtons)
{
//add separator
_pTBB[i].iBitmap = 0;
@ -181,7 +194,7 @@ bool ToolBar::init( HINSTANCE hInst, HWND hPere, toolBarStatusType type, ToolBar
++i;
//add plugin buttons
for (size_t j = 0; j < _nbDynButtons ; ++j, ++i)
for (size_t j = 0; j < _nbDynButtons && i < _nbTotalButtons; ++j, ++i)
{
cmd = _vDynBtnReg[j]._message;
++bmpIndex;
@ -318,7 +331,7 @@ void ToolBar::reset(bool create)
// Send the TB_BUTTONSTRUCTSIZE message, which is required for
// backward compatibility.
::SendMessage(_hSelf, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
::SendMessage(_hSelf, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_HIDECLIPPEDBUTTONS | TBSTYLE_EX_DOUBLEBUFFER);
::SendMessage(_hSelf, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_HIDECLIPPEDBUTTONS | TBSTYLE_EX_DOUBLEBUFFER);
change2CustomIconsIfAny();
}