// This file is part of Notepad++ project // Copyright (C)2003 Don HO // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // Note that the GPL places important restrictions on "derived works", yet // it does not provide a detailed definition of that term. To avoid // misunderstandings, we consider an application to constitute a // "derivative work" for the purpose of this license if it does any of the // following: // 1. Integrates source code from Notepad++. // 2. Integrates/includes/aggregates Notepad++ into a proprietary executable // installer, such as those produced by InstallShield. // 3. Links to a library or executes a program that does any of the above. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "precompiledHeaders.h" #include "ToolBar.h" #include "Shortcut.h" #include "Parameters.h" #include "FindReplaceDlg_rc.h" const int WS_TOOLBARSTYLE = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS |TBSTYLE_FLAT | CCS_TOP | BTNS_AUTOSIZE | CCS_NOPARENTALIGN | CCS_NORESIZE | CCS_NODIVIDER; void ToolBar::initTheme(TiXmlDocument *toolIconsDocRoot) { _toolIcons = toolIconsDocRoot->FirstChild(TEXT("NotepadPlus")); if (_toolIcons) { _toolIcons = _toolIcons->FirstChild(TEXT("ToolBarIcons")); if (_toolIcons) { _toolIcons = _toolIcons->FirstChild(TEXT("Theme")); if (_toolIcons) { const TCHAR *themeDir = (_toolIcons->ToElement())->Attribute(TEXT("pathPrefix")); for (TiXmlNode *childNode = _toolIcons->FirstChildElement(TEXT("Icon")); childNode ; childNode = childNode->NextSibling(TEXT("Icon"))) { int iIcon; const TCHAR *res = (childNode->ToElement())->Attribute(TEXT("id"), &iIcon); if (res) { TiXmlNode *grandChildNode = childNode->FirstChildElement(TEXT("normal")); if (grandChildNode) { TiXmlNode *valueNode = grandChildNode->FirstChild(); //putain, enfin!!! if (valueNode) { generic_string locator = themeDir?themeDir:TEXT(""); locator += valueNode->Value(); _customIconVect.push_back(iconLocator(0, iIcon, locator)); } } grandChildNode = childNode->FirstChildElement(TEXT("hover")); if (grandChildNode) { TiXmlNode *valueNode = grandChildNode->FirstChild(); //putain, enfin!!! if (valueNode) { generic_string locator = themeDir?themeDir:TEXT(""); locator += valueNode->Value(); _customIconVect.push_back(iconLocator(1, iIcon, locator)); } } grandChildNode = childNode->FirstChildElement(TEXT("disabled")); if (grandChildNode) { TiXmlNode *valueNode = grandChildNode->FirstChild(); //putain, enfin!!! if (valueNode) { generic_string locator = themeDir?themeDir:TEXT(""); locator += valueNode->Value(); _customIconVect.push_back(iconLocator(2, iIcon, locator)); } } } } } } } } bool ToolBar::init( HINSTANCE hInst, HWND hPere, toolBarStatusType type, ToolBarButtonUnit *buttonUnitArray, int arraySize) { Window::init(hInst, hPere); _state = type; int iconSize = NppParameters::getInstance()->_dpiManager.scaleX(_state == TB_LARGE?32:16); _toolBarIcons.init(buttonUnitArray, arraySize); _toolBarIcons.create(_hInst, iconSize); INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_WIN95_CLASSES|ICC_COOL_CLASSES|ICC_BAR_CLASSES|ICC_USEREX_CLASSES; InitCommonControlsEx(&icex); //Create the list of buttons _nrButtons = arraySize; _nrDynButtons = _vDynBtnReg.size(); _nrTotalButtons = _nrButtons + (_nrDynButtons ? _nrDynButtons + 1 : 0); _pTBB = new TBBUTTON[_nrTotalButtons]; //add one for the extra separator int cmd = 0; int bmpIndex = -1, style; size_t i = 0; for (; i < _nrButtons ; ++i) { cmd = buttonUnitArray[i]._cmdID; if (cmd != 0) { ++bmpIndex; style = BTNS_BUTTON; } else { style = BTNS_SEP; } _pTBB[i].iBitmap = (cmd != 0?bmpIndex:0); _pTBB[i].idCommand = cmd; _pTBB[i].fsState = TBSTATE_ENABLED; _pTBB[i].fsStyle = (BYTE)style; _pTBB[i].dwData = 0; _pTBB[i].iString = 0; } if (_nrDynButtons > 0) { //add separator _pTBB[i].iBitmap = 0; _pTBB[i].idCommand = 0; _pTBB[i].fsState = TBSTATE_ENABLED; _pTBB[i].fsStyle = BTNS_SEP; _pTBB[i].dwData = 0; _pTBB[i].iString = 0; ++i; //add plugin buttons for (size_t j = 0; j < _nrDynButtons ; ++j, ++i) { cmd = _vDynBtnReg[j].message; ++bmpIndex; _pTBB[i].iBitmap = bmpIndex; _pTBB[i].idCommand = cmd; _pTBB[i].fsState = TBSTATE_ENABLED; _pTBB[i].fsStyle = BTNS_BUTTON; _pTBB[i].dwData = 0; _pTBB[i].iString = 0; } } reset(true); //load icons etc return true; } void ToolBar::destroy() { if (_pRebar) { _pRebar->removeBand(_rbBand.wID); _pRebar = NULL; } delete [] _pTBB; ::DestroyWindow(_hSelf); _hSelf = NULL; _toolBarIcons.destroy(); }; int ToolBar::getWidth() const { RECT btnRect; int totalWidth = 0; for(size_t i = 0; i < _nrCurrentButtons; ++i) { ::SendMessage(_hSelf, TB_GETITEMRECT, i, (LPARAM)&btnRect); totalWidth += btnRect.right - btnRect.left; } return totalWidth; } int ToolBar::getHeight() const { DWORD size = (DWORD)SendMessage(_hSelf, TB_GETBUTTONSIZE, 0, 0); DWORD padding = (DWORD)SendMessage(_hSelf, TB_GETPADDING, 0,0); int totalHeight = HIWORD(size) + HIWORD(padding); return totalHeight; } void ToolBar::reduce() { if (_state == TB_SMALL) return; int iconDpiDynamicalSize = NppParameters::getInstance()->_dpiManager.scaleX(16); _toolBarIcons.resizeIcon(iconDpiDynamicalSize); bool recreate = (_state == TB_STANDARD); setState(TB_SMALL); reset(recreate); //recreate toolbar if std icons were used Window::redraw(); } void ToolBar::enlarge() { if (_state == TB_LARGE) return; int iconDpiDynamicalSize = NppParameters::getInstance()->_dpiManager.scaleX(32); _toolBarIcons.resizeIcon(iconDpiDynamicalSize); bool recreate = (_state == TB_STANDARD); setState(TB_LARGE); reset(recreate); //recreate toolbar if std icons were used Window::redraw(); } void ToolBar::setToUglyIcons() { if (_state == TB_STANDARD) return; bool recreate = true; setState(TB_STANDARD); reset(recreate); //must recreate toolbar if setting to internal bitmaps Window::redraw(); } void ToolBar::reset(bool create) { if(create && _hSelf) { //Store current button state information TBBUTTON tempBtn; for(size_t i = 0; i < _nrCurrentButtons; ++i) { ::SendMessage(_hSelf, TB_GETBUTTON, (WPARAM)i, (LPARAM)&tempBtn); _pTBB[i].fsState = tempBtn.fsState; } ::DestroyWindow(_hSelf); _hSelf = NULL; } if(!_hSelf) { _hSelf = ::CreateWindowEx( WS_EX_PALETTEWINDOW, TOOLBARCLASSNAME, TEXT(""), WS_TOOLBARSTYLE, 0, 0, 0, 0, _hParent, NULL, _hInst, 0); // Send the TB_BUTTONSTRUCTSIZE message, which is required for // backward compatibility. ::SendMessage(_hSelf, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0); ::SendMessage(_hSelf, TB_SETEXTENDEDSTYLE, 0, (LPARAM)TBSTYLE_EX_HIDECLIPPEDBUTTONS); } if (!_hSelf) { throw std::runtime_error("ToolBar::reset : CreateWindowEx() function return null"); } if (_state != TB_STANDARD) { //If non standard icons, use custom imagelists setDefaultImageList(); setHotImageList(); setDisableImageList(); } else { //Else set the internal imagelist with standard bitmaps int iconDpiDynamicalSize = NppParameters::getInstance()->_dpiManager.scaleX(16);; ::SendMessage(_hSelf, TB_SETBITMAPSIZE, 0, MAKELPARAM(iconDpiDynamicalSize, iconDpiDynamicalSize)); //TBADDBITMAP addbmp = {_hInst, 0}; TBADDBITMAP addbmp = {0, 0}; TBADDBITMAP addbmpdyn = {0, 0}; for (size_t i = 0 ; i < _nrButtons ; ++i) { HBITMAP hBmp = (HBITMAP)::LoadImage(_hInst, MAKEINTRESOURCE(_toolBarIcons.getStdIconAt(i)), IMAGE_BITMAP, iconDpiDynamicalSize, iconDpiDynamicalSize, LR_LOADMAP3DCOLORS | LR_LOADTRANSPARENT); addbmp.nID = (UINT_PTR)hBmp; //addbmp.nID = _toolBarIcons.getStdIconAt(i); ::SendMessage(_hSelf, TB_ADDBITMAP, 1, (LPARAM)&addbmp); } if (_nrDynButtons > 0) { for (size_t j = 0; j < _nrDynButtons; ++j) { addbmpdyn.nID = (UINT_PTR)_vDynBtnReg.at(j).hBmp; ::SendMessage(_hSelf, TB_ADDBITMAP, 1, (LPARAM)&addbmpdyn); } } } if (create) { //if the toolbar has been recreated, readd the buttons size_t nrBtnToAdd = (_state == TB_STANDARD?_nrTotalButtons:_nrButtons); _nrCurrentButtons = nrBtnToAdd; WORD btnSize = (_state == TB_LARGE?32:16); ::SendMessage(_hSelf, TB_SETBUTTONSIZE , (WPARAM)0, (LPARAM)MAKELONG (btnSize, btnSize)); ::SendMessage(_hSelf, TB_ADDBUTTONS, (WPARAM)nrBtnToAdd, (LPARAM)_pTBB); } ::SendMessage(_hSelf, TB_AUTOSIZE, 0, 0); if (_pRebar) { _rbBand.hwndChild = getHSelf(); _rbBand.cxMinChild = 0; _rbBand.cyIntegral = 1; _rbBand.cyMinChild = _rbBand.cyMaxChild = getHeight(); _rbBand.cxIdeal = getWidth(); _pRebar->reNew(REBAR_BAR_TOOLBAR, &_rbBand); } } void ToolBar::registerDynBtn(UINT messageID, toolbarIcons* tIcon) { // Note: Register of buttons only possible before init! if ((_hSelf == NULL) && (messageID != 0) && (tIcon->hToolbarBmp != NULL)) { tDynamicList dynList; dynList.message = messageID; dynList.hBmp = tIcon->hToolbarBmp; dynList.hIcon = tIcon->hToolbarIcon; _vDynBtnReg.push_back(dynList); } } void ToolBar::doPopop(POINT chevPoint) { //first find hidden buttons int width = Window::getWidth(); size_t start = 0; RECT btnRect = {0,0,0,0}; while(start < _nrCurrentButtons) { ::SendMessage(_hSelf, TB_GETITEMRECT, start, (LPARAM)&btnRect); if(btnRect.right > width) break; ++start; } if (start < _nrCurrentButtons) { //some buttons are hidden HMENU menu = ::CreatePopupMenu(); int cmd; generic_string text; while (start < _nrCurrentButtons) { cmd = _pTBB[start].idCommand; getNameStrFromCmd(cmd, text); if (_pTBB[start].idCommand != 0) { if (::SendMessage(_hSelf, TB_ISBUTTONENABLED, cmd, 0) != 0) AppendMenu(menu, MF_ENABLED, cmd, text.c_str()); else AppendMenu(menu, MF_DISABLED|MF_GRAYED, cmd, text.c_str()); } else AppendMenu(menu, MF_SEPARATOR, 0, TEXT("")); ++start; } TrackPopupMenu(menu, 0, chevPoint.x, chevPoint.y, 0, _hSelf, NULL); } } void ToolBar::addToRebar(ReBar * rebar) { if (_pRebar) return; _pRebar = rebar; ZeroMemory(&_rbBand, REBARBAND_SIZE); _rbBand.cbSize = REBARBAND_SIZE; _rbBand.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_ID; _rbBand.fStyle = RBBS_VARIABLEHEIGHT | RBBS_USECHEVRON; _rbBand.hwndChild = getHSelf(); _rbBand.wID = REBAR_BAR_TOOLBAR; //ID REBAR_BAR_TOOLBAR for toolbar _rbBand.cxMinChild = 0; _rbBand.cyIntegral = 1; _rbBand.cyMinChild = _rbBand.cyMaxChild = getHeight(); _rbBand.cxIdeal = _rbBand.cx = getWidth(); _pRebar->addBand(&_rbBand, true); _rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_SIZE; } void ReBar::init(HINSTANCE hInst, HWND hPere) { Window::init(hInst, hPere); _hSelf = CreateWindowEx(WS_EX_TOOLWINDOW, REBARCLASSNAME, NULL, WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|RBS_VARHEIGHT| RBS_BANDBORDERS | CCS_NODIVIDER | CCS_NOPARENTALIGN, 0,0,0,0, _hParent, NULL, _hInst, NULL); REBARINFO rbi; ZeroMemory(&rbi, sizeof(REBARINFO)); rbi.cbSize = sizeof(REBARINFO); rbi.fMask = 0; rbi.himl = (HIMAGELIST)NULL; ::SendMessage(_hSelf, RB_SETBARINFO, 0, (LPARAM)&rbi); } bool ReBar::addBand(REBARBANDINFO * rBand, bool useID) { if (rBand->fMask & RBBIM_STYLE) { if (!(rBand->fStyle & RBBS_NOGRIPPER)) rBand->fStyle |= RBBS_GRIPPERALWAYS; } else rBand->fStyle = RBBS_GRIPPERALWAYS; rBand->fMask |= RBBIM_ID | RBBIM_STYLE; if (useID) { if (isIDTaken(rBand->wID)) return false; } else { rBand->wID = getNewID(); } ::SendMessage(_hSelf, RB_INSERTBAND, (WPARAM)-1, (LPARAM)rBand); //add to end of list return true; } void ReBar::reNew(int id, REBARBANDINFO * rBand) { int index = (int)SendMessage(_hSelf, RB_IDTOINDEX, (WPARAM)id, 0); ::SendMessage(_hSelf, RB_SETBANDINFO, (WPARAM)index, (LPARAM)rBand); }; void ReBar::removeBand(int id) { int index = (int)SendMessage(_hSelf, RB_IDTOINDEX, (WPARAM)id, 0); if (id >= REBAR_BAR_EXTERNAL) releaseID(id); ::SendMessage(_hSelf, RB_DELETEBAND, (WPARAM)index, (LPARAM)0); } void ReBar::setIDVisible(int id, bool show) { int index = (int)SendMessage(_hSelf, RB_IDTOINDEX, (WPARAM)id, 0); if (index == -1 ) return; //error REBARBANDINFO rbBand; ZeroMemory(&rbBand, REBARBAND_SIZE); rbBand.cbSize = REBARBAND_SIZE; rbBand.fMask = RBBIM_STYLE; ::SendMessage(_hSelf, RB_GETBANDINFO, (WPARAM)index, (LPARAM)&rbBand); if (show) rbBand.fStyle &= (RBBS_HIDDEN ^ -1); else rbBand.fStyle |= RBBS_HIDDEN; ::SendMessage(_hSelf, RB_SETBANDINFO, (WPARAM)index, (LPARAM)&rbBand); } bool ReBar::getIDVisible(int id) { int index = (int)SendMessage(_hSelf, RB_IDTOINDEX, (WPARAM)id, 0); if (index == -1 ) return false; //error REBARBANDINFO rbBand; ZeroMemory(&rbBand, REBARBAND_SIZE); rbBand.cbSize = REBARBAND_SIZE; rbBand.fMask = RBBIM_STYLE; ::SendMessage(_hSelf, RB_GETBANDINFO, (WPARAM)index, (LPARAM)&rbBand); return ((rbBand.fStyle & RBBS_HIDDEN) == 0); } void ReBar::setGrayBackground(int id) { int index = (int)SendMessage(_hSelf, RB_IDTOINDEX, (WPARAM)id, 0); if (index == -1 ) return; //error REBARBANDINFO rbBand; ZeroMemory(&rbBand, REBARBAND_SIZE); rbBand.cbSize = REBARBAND_SIZE; rbBand.fMask = RBBIM_BACKGROUND; rbBand.hbmBack = LoadBitmap((HINSTANCE)::GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_INCREMENTAL_BG)); ::SendMessage(_hSelf, RB_SETBANDINFO, (WPARAM)index, (LPARAM)&rbBand); } int ReBar::getNewID() { int idToUse = REBAR_BAR_EXTERNAL; int curVal = 0; size_t size = usedIDs.size(); for(size_t i = 0; i < size; ++i) { curVal = usedIDs.at(i); if (curVal < idToUse) { continue; } else if (curVal == idToUse) { ++idToUse; } else { break; //found gap } } usedIDs.push_back(idToUse); return idToUse; } void ReBar::releaseID(int id) { size_t size = usedIDs.size(); for(size_t i = 0; i < size; ++i) { if (usedIDs.at(i) == id) { usedIDs.erase(usedIDs.begin()+i); break; } } } bool ReBar::isIDTaken(int id) { size_t size = usedIDs.size(); for(size_t i = 0; i < size; ++i) { if (usedIDs.at(i) == id) { return true; } } return false; }