BOOL Notepad_plus::notify(SCNotification *notification) { //Important, keep track of which element generated the message bool isFromPrimary = (_mainEditView.getHSelf() == notification->nmhdr.hwndFrom || _mainDocTab.getHSelf() == notification->nmhdr.hwndFrom); bool isFromSecondary = !isFromPrimary && (_subEditView.getHSelf() == notification->nmhdr.hwndFrom || _subDocTab.getHSelf() == notification->nmhdr.hwndFrom); ScintillaEditView * notifyView = isFromPrimary?&_mainEditView:&_subEditView; DocTabView *notifyDocTab = isFromPrimary?&_mainDocTab:&_subDocTab; TBHDR * tabNotification = (TBHDR*) notification; switch (notification->nmhdr.code) { case SCN_MODIFIED: { static bool prevWasEdit = false; if (notification->modificationType & (SC_MOD_DELETETEXT | SC_MOD_INSERTTEXT)) { _pEditView->updateBeginEndSelectPosition(notification->modificationType & SC_MOD_INSERTTEXT, notification->position, notification->length); prevWasEdit = true; _linkTriggered = true; ::InvalidateRect(notifyView->getHSelf(), NULL, TRUE); } if (notification->modificationType & SC_MOD_CHANGEFOLD) { if (prevWasEdit) { notifyView->foldChanged(notification->line, notification->foldLevelNow, notification->foldLevelPrev); prevWasEdit = false; } } else if (!(notification->modificationType & (SC_MOD_DELETETEXT | SC_MOD_INSERTTEXT))) { prevWasEdit = false; } } break; case SCN_SAVEPOINTREACHED: case SCN_SAVEPOINTLEFT: { Buffer * buf = 0; if (isFromPrimary) { buf = _mainEditView.getCurrentBuffer(); } else if (isFromSecondary) { buf = _subEditView.getCurrentBuffer(); } else { //Done by invisibleEditView? BufferID id = BUFFER_INVALID; if (notification->nmhdr.hwndFrom == _invisibleEditView.getHSelf()) { id = MainFileManager->getBufferFromDocument(_invisibleEditView.execute(SCI_GETDOCPOINTER)); } else if (notification->nmhdr.hwndFrom == _fileEditView.getHSelf()) { id = MainFileManager->getBufferFromDocument(_fileEditView.execute(SCI_GETDOCPOINTER)); } else { break; //wrong scintilla } if (id != BUFFER_INVALID) { buf = MainFileManager->getBufferByID(id); } else { break; } } bool isDirty = notification->nmhdr.code == SCN_SAVEPOINTLEFT; buf->setDirty(isDirty); break; } case SCN_MODIFYATTEMPTRO : // on fout rien break; case SCN_KEY: break; case TCN_TABDROPPEDOUTSIDE: case TCN_TABDROPPED: { TabBarPlus *sender = reinterpret_cast<TabBarPlus *>(notification->nmhdr.idFrom); bool isInCtrlStat = (::GetKeyState(VK_LCONTROL) & 0x80000000) != 0; if (notification->nmhdr.code == TCN_TABDROPPEDOUTSIDE) { POINT p = sender->getDraggingPoint(); //It's the coordinate of screen, so we can call //"WindowFromPoint" function without converting the point HWND hWin = ::WindowFromPoint(p); if (hWin == _pEditView->getHSelf()) // In the same view group { if (!_tabPopupDropMenu.isCreated()) { TCHAR goToView[32] = TEXT("Move to other view"); TCHAR cloneToView[32] = TEXT("Clone to other View"); vector<MenuItemUnit> itemUnitArray; itemUnitArray.push_back(MenuItemUnit(IDM_VIEW_GOTO_ANOTHER_VIEW, goToView)); itemUnitArray.push_back(MenuItemUnit(IDM_VIEW_CLONE_TO_ANOTHER_VIEW, cloneToView)); _tabPopupDropMenu.create(_pPublicInterface->getHSelf(), itemUnitArray, _mainMenuHandle); _nativeLangSpeaker.changeLangTabDrapContextMenu(_tabPopupDropMenu.getMenuHandle()); } _tabPopupDropMenu.display(p); } else if ((hWin == _pNonDocTab->getHSelf()) || (hWin == _pNonEditView->getHSelf())) // In the another view group { docGotoAnotherEditView(isInCtrlStat?TransferClone:TransferMove); }/* else if ((hWin == _pProjectPanel_1->getTreeHandle())) { //printStr(TEXT("IN!!!")); }*/ else { RECT nppZone; ::GetWindowRect(_pPublicInterface->getHSelf(), &nppZone); bool isInNppZone = (((p.x >= nppZone.left) && (p.x <= nppZone.right)) && (p.y >= nppZone.top) && (p.y <= nppZone.bottom)); if (isInNppZone) { // Do nothing return TRUE; } generic_string quotFileName = TEXT("\""); quotFileName += _pEditView->getCurrentBuffer()->getFullPathName(); quotFileName += TEXT("\""); COPYDATASTRUCT fileNamesData; fileNamesData.dwData = COPYDATA_FILENAMES; fileNamesData.lpData = (void *)quotFileName.c_str(); fileNamesData.cbData = long(quotFileName.length() + 1)*(sizeof(TCHAR)); HWND hWinParent = ::GetParent(hWin); TCHAR className[MAX_PATH]; ::GetClassName(hWinParent,className, sizeof(className)); if (lstrcmp(className, _pPublicInterface->getClassName()) == 0 && hWinParent != _pPublicInterface->getHSelf()) // another Notepad++ { int index = _pDocTab->getCurrentTabIndex(); BufferID bufferToClose = notifyDocTab->getBufferByIndex(index); Buffer * buf = MainFileManager->getBufferByID(bufferToClose); int iView = isFromPrimary?MAIN_VIEW:SUB_VIEW; if (buf->isDirty()) { generic_string msg, title; _nativeLangSpeaker.messageBox("CannotMoveDoc", _pPublicInterface->getHSelf(), TEXT("Document is modified, save it then try again."), TEXT("Move to new Notepad++ Instance"), MB_OK); } else { ::SendMessage(hWinParent, NPPM_INTERNAL_SWITCHVIEWFROMHWND, 0, (LPARAM)hWin); ::SendMessage(hWinParent, WM_COPYDATA, (WPARAM)_pPublicInterface->getHinst(), (LPARAM)&fileNamesData); if (!isInCtrlStat) { fileClose(bufferToClose, iView); if (noOpenedDoc()) ::SendMessage(_pPublicInterface->getHSelf(), WM_CLOSE, 0, 0); } } } else // Not Notepad++, we open it here { docOpenInNewInstance(isInCtrlStat?TransferClone:TransferMove, p.x, p.y); } } } //break; sender->resetDraggingPoint(); return TRUE; } case TCN_TABDELETE: { int index = tabNotification->tabOrigin; BufferID bufferToClose = notifyDocTab->getBufferByIndex(index); Buffer * buf = MainFileManager->getBufferByID(bufferToClose); int iView = isFromPrimary?MAIN_VIEW:SUB_VIEW; if (buf->isDirty()) { //activate and use fileClose() (for save and abort) activateBuffer(bufferToClose, iView); fileClose(bufferToClose, iView); break; } int open = 1; if (isFromPrimary || isFromSecondary) open = notifyDocTab->nbItem(); doClose(bufferToClose, iView); //if (open == 1 && canHideView(iView)) // hideView(iView); break; } case TCN_SELCHANGE: { int iView = -1; if (notification->nmhdr.hwndFrom == _mainDocTab.getHSelf()) { iView = MAIN_VIEW; } else if (notification->nmhdr.hwndFrom == _subDocTab.getHSelf()) { iView = SUB_VIEW; } else { break; } switchEditViewTo(iView); BufferID bufid = _pDocTab->getBufferByIndex(_pDocTab->getCurrentTabIndex()); if (bufid != BUFFER_INVALID) activateBuffer(bufid, iView); break; } case NM_CLICK : { if (notification->nmhdr.hwndFrom == _statusBar.getHSelf()) { LPNMMOUSE lpnm = (LPNMMOUSE)notification; if (lpnm->dwItemSpec == DWORD(STATUSBAR_TYPING_MODE)) { bool isOverTypeMode = (_pEditView->execute(SCI_GETOVERTYPE) != 0); _pEditView->execute(SCI_SETOVERTYPE, !isOverTypeMode); _statusBar.setText((_pEditView->execute(SCI_GETOVERTYPE))?TEXT("OVR"):TEXT("INS"), STATUSBAR_TYPING_MODE); } } else if (notification->nmhdr.hwndFrom == _mainDocTab.getHSelf()) { switchEditViewTo(MAIN_VIEW); } else if (notification->nmhdr.hwndFrom == _subDocTab.getHSelf()) { switchEditViewTo(SUB_VIEW); } break; } case NM_DBLCLK : { if (notification->nmhdr.hwndFrom == _statusBar.getHSelf()) { LPNMMOUSE lpnm = (LPNMMOUSE)notification; if (lpnm->dwItemSpec == DWORD(STATUSBAR_CUR_POS)) { bool isFirstTime = !_goToLineDlg.isCreated(); _goToLineDlg.doDialog(_nativeLangSpeaker.isRTL()); if (isFirstTime) _nativeLangSpeaker.changeDlgLang(_goToLineDlg.getHSelf(), "GoToLine"); } else if (lpnm->dwItemSpec == DWORD(STATUSBAR_DOC_SIZE)) { command(IDM_VIEW_SUMMARY); } } break; } case NM_RCLICK : { POINT p; ::GetCursorPos(&p); if (notification->nmhdr.hwndFrom == _mainDocTab.getHSelf()) { switchEditViewTo(MAIN_VIEW); } else if (notification->nmhdr.hwndFrom == _subDocTab.getHSelf()) { switchEditViewTo(SUB_VIEW); } else if (_pFileSwitcherPanel && notification->nmhdr.hwndFrom == _pFileSwitcherPanel->getHSelf()) { // Already switched, so do nothing here. if (_pFileSwitcherPanel->nbSelectedFiles() > 1) { if (!_fileSwitcherMultiFilePopupMenu.isCreated()) { vector<MenuItemUnit> itemUnitArray; itemUnitArray.push_back(MenuItemUnit(IDM_FILESWITCHER_FILESCLOSE, TEXT("Close Selected files"))); itemUnitArray.push_back(MenuItemUnit(IDM_FILESWITCHER_FILESCLOSEOTHERS, TEXT("Close others files"))); _fileSwitcherMultiFilePopupMenu.create(_pPublicInterface->getHSelf(), itemUnitArray); _nativeLangSpeaker.changeLangTabContextMenu(_fileSwitcherMultiFilePopupMenu.getMenuHandle()); } _fileSwitcherMultiFilePopupMenu.display(p); return TRUE; } } else // From tool bar or Status Bar return TRUE; //break; if (!_tabPopupMenu.isCreated()) { vector<MenuItemUnit> itemUnitArray; itemUnitArray.push_back(MenuItemUnit(IDM_FILE_CLOSE, TEXT("Close"))); itemUnitArray.push_back(MenuItemUnit(IDM_FILE_CLOSEALL_BUT_CURRENT, TEXT("Close All BUT This"))); itemUnitArray.push_back(MenuItemUnit(IDM_FILE_CLOSEALL_TOLEFT, TEXT("Close All to the Left"))); itemUnitArray.push_back(MenuItemUnit(IDM_FILE_CLOSEALL_TORIGHT, TEXT("Close All to the Right"))); itemUnitArray.push_back(MenuItemUnit(IDM_FILE_SAVE, TEXT("Save"))); itemUnitArray.push_back(MenuItemUnit(IDM_FILE_SAVEAS, TEXT("Save As..."))); itemUnitArray.push_back(MenuItemUnit(IDM_FILE_RENAME, TEXT("Rename"))); itemUnitArray.push_back(MenuItemUnit(IDM_FILE_DELETE, TEXT("Move to Recycle Bin"))); itemUnitArray.push_back(MenuItemUnit(IDM_FILE_RELOAD, TEXT("Reload"))); itemUnitArray.push_back(MenuItemUnit(IDM_FILE_PRINT, TEXT("Print"))); itemUnitArray.push_back(MenuItemUnit(0, NULL)); itemUnitArray.push_back(MenuItemUnit(IDM_FILE_OPEN_FOLDER, TEXT("Open Containing Folder in Explorer"))); itemUnitArray.push_back(MenuItemUnit(IDM_FILE_OPEN_CMD, TEXT("Open Containing Folder in cmd"))); itemUnitArray.push_back(MenuItemUnit(0, NULL)); itemUnitArray.push_back(MenuItemUnit(IDM_EDIT_SETREADONLY, TEXT("Read-Only"))); itemUnitArray.push_back(MenuItemUnit(IDM_EDIT_CLEARREADONLY, TEXT("Clear Read-Only Flag"))); itemUnitArray.push_back(MenuItemUnit(0, NULL)); itemUnitArray.push_back(MenuItemUnit(IDM_EDIT_FULLPATHTOCLIP, TEXT("Full File Path to Clipboard"))); itemUnitArray.push_back(MenuItemUnit(IDM_EDIT_FILENAMETOCLIP, TEXT("Filename to Clipboard"))); itemUnitArray.push_back(MenuItemUnit(IDM_EDIT_CURRENTDIRTOCLIP, TEXT("Current Dir. Path to Clipboard"))); itemUnitArray.push_back(MenuItemUnit(0, NULL)); itemUnitArray.push_back(MenuItemUnit(IDM_VIEW_GOTO_ANOTHER_VIEW, TEXT("Move to Other View"))); itemUnitArray.push_back(MenuItemUnit(IDM_VIEW_CLONE_TO_ANOTHER_VIEW, TEXT("Clone to Other View"))); itemUnitArray.push_back(MenuItemUnit(IDM_VIEW_GOTO_NEW_INSTANCE, TEXT("Move to New Instance"))); itemUnitArray.push_back(MenuItemUnit(IDM_VIEW_LOAD_IN_NEW_INSTANCE, TEXT("Open in New Instance"))); _tabPopupMenu.create(_pPublicInterface->getHSelf(), itemUnitArray); _nativeLangSpeaker.changeLangTabContextMenu(_tabPopupMenu.getMenuHandle()); } bool isEnable = ((::GetMenuState(_mainMenuHandle, IDM_FILE_SAVE, MF_BYCOMMAND)&MF_DISABLED) == 0); _tabPopupMenu.enableItem(IDM_FILE_SAVE, isEnable); Buffer * buf = _pEditView->getCurrentBuffer(); bool isUserReadOnly = buf->getUserReadOnly(); _tabPopupMenu.checkItem(IDM_EDIT_SETREADONLY, isUserReadOnly); bool isSysReadOnly = buf->getFileReadOnly(); _tabPopupMenu.enableItem(IDM_EDIT_SETREADONLY, !isSysReadOnly); _tabPopupMenu.enableItem(IDM_EDIT_CLEARREADONLY, isSysReadOnly); bool isFileExisting = PathFileExists(buf->getFullPathName()) != FALSE; _tabPopupMenu.enableItem(IDM_FILE_DELETE, isFileExisting); _tabPopupMenu.enableItem(IDM_FILE_RENAME, isFileExisting); bool isDirty = buf->isDirty(); bool isUntitled = buf->isUntitled(); _tabPopupMenu.enableItem(IDM_VIEW_GOTO_NEW_INSTANCE, !(isDirty||isUntitled)); _tabPopupMenu.enableItem(IDM_VIEW_LOAD_IN_NEW_INSTANCE, !(isDirty||isUntitled)); _tabPopupMenu.display(p); return TRUE; } case SCN_MARGINCLICK: { if (notification->nmhdr.hwndFrom == _mainEditView.getHSelf()) switchEditViewTo(MAIN_VIEW); else if (notification->nmhdr.hwndFrom == _subEditView.getHSelf()) switchEditViewTo(SUB_VIEW); int lineClick = int(_pEditView->execute(SCI_LINEFROMPOSITION, notification->position)); if (notification->margin == ScintillaEditView::_SC_MARGE_FOLDER) { _pEditView->marginClick(notification->position, notification->modifiers); if (_pDocMap) _pDocMap->fold(lineClick, _pEditView->isFolded(lineClick)); } else if ((notification->margin == ScintillaEditView::_SC_MARGE_SYBOLE) && !notification->modifiers) { if (!_pEditView->markerMarginClick(lineClick)) bookmarkToggle(lineClick); } break; } case SCN_FOLDINGSTATECHANGED : { if ((notification->nmhdr.hwndFrom == _mainEditView.getHSelf()) || (notification->nmhdr.hwndFrom == _subEditView.getHSelf())) { int lineClicked = notification->line; if (!_isFolding) { int urlAction = (NppParameters::getInstance())->getNppGUI()._styleURL; if ((urlAction == 1) || (urlAction == 2)) addHotSpot(); } if (_pDocMap) _pDocMap->fold(lineClicked, _pEditView->isFolded(lineClicked)); } return TRUE; } case SCN_CHARADDED: { const NppGUI & nppGui = NppParameters::getInstance()->getNppGUI(); bool indentMaintain = nppGui._maitainIndent; if (indentMaintain) MaintainIndentation(static_cast<TCHAR>(notification->ch)); AutoCompletion * autoC = isFromPrimary?&_autoCompleteMain:&_autoCompleteSub; if (nppGui._matchedPairConf.hasAnyPairsPair()) autoC->insertMatchedChars(notification->ch, nppGui._matchedPairConf); autoC->update(notification->ch); break; } case SCN_DOUBLECLICK : { if(notification->modifiers == SCMOD_CTRL) { const NppGUI & nppGUI = NppParameters::getInstance()->getNppGUI(); std::string bufstring; unsigned int position_of_click; // Anonymous scope to limit use of the buf pointer (much easier to deal with std::string). { char *buf; int length; if(nppGUI._delimiterSelectionOnEntireDocument) { // Get entire document. length = notifyView->execute(SCI_GETLENGTH); buf = new char[length + 1]; notifyView->execute(SCI_GETTEXT, (LPARAM)(length + 1), (WPARAM)buf); // For some reason Ctrl+DoubleClick on an empty line means that notification->position == 1. // In that case we use SCI_GETCURRENTPOS to get the position. if(notification->position != -1) position_of_click = notification->position; else position_of_click = int(_pEditView->execute(SCI_GETCURRENTPOS)); } else { // Get single line. length = notifyView->execute(SCI_GETCURLINE); buf = new char[length + 1]; notifyView->execute(SCI_GETCURLINE, (WPARAM)length, (LPARAM)buf); // Compute the position of the click (relative to the beginning of the line). const int line_position = notifyView->execute(SCI_POSITIONFROMLINE, notifyView->getCurrentLineNumber()); position_of_click = notification->position - line_position; } bufstring = buf; delete [] buf; } int leftmost_position = -1; int rightmost_position = -1; if(nppGUI._rightmostDelimiter == nppGUI._leftmostDelimiter) { // If the delimiters are the same (e.g. they are both a quotation mark), choose the ones // which are closest to the clicked position. for(unsigned int i = position_of_click; i >= 0; --i) { if(bufstring.at(i) == nppGUI._leftmostDelimiter) { // Respect escaped quotation marks. if(nppGUI._leftmostDelimiter == '"') { if(! (i > 0 && bufstring.at(i - 1) == '\\')) { leftmost_position = i; break; } } else { leftmost_position = i; break; } } } if(leftmost_position == -1) break; // Scan for right delimiter. for(unsigned int i = position_of_click; i < bufstring.length(); ++i) { if(bufstring.at(i) == nppGUI._rightmostDelimiter) { // Respect escaped quotation marks. if(nppGUI._rightmostDelimiter == '"') { if(! (i > 0 && bufstring.at(i - 1) == '\\')) { rightmost_position = i; break; } } else { rightmost_position = i; break; } } } } else { // Find matching pairs of delimiters (e.g. parantheses). // The pair where the distance from the left delimiter to position_of_click is at a minimum is the one we're looking for. // Of course position_of_click must lie between the delimiters. // This logic is required to handle cases like this: // (size_t i = function(); i < _buffers.size(); i++) std::stack<unsigned int> leftmost_delimiter_positions; for(unsigned int i = 0; i < bufstring.length(); ++i) { if(bufstring.at(i) == nppGUI._leftmostDelimiter) leftmost_delimiter_positions.push(i); else if(bufstring.at(i) == nppGUI._rightmostDelimiter && ! leftmost_delimiter_positions.empty()) { unsigned int matching_leftmost = leftmost_delimiter_positions.top(); leftmost_delimiter_positions.pop(); // We have either 1) chosen neither the left- or rightmost position, or 2) chosen both left- and rightmost position. assert( (leftmost_position == -1 && rightmost_position == -1) || (leftmost_position >= 0 && rightmost_position >= 0) ); // Note: cast of leftmost_position to unsigned int is safe, since if leftmost_position is not -1 then it is guaranteed to be positive. // If it was possible, leftmost_position and rightmost_position should be of type optional<unsigned int>. if( matching_leftmost <= position_of_click && i >= position_of_click && (leftmost_position == -1 || matching_leftmost > (unsigned int)leftmost_position) ) { leftmost_position = matching_leftmost; rightmost_position = i; } } } } // Set selection to the position we found (if any). if(rightmost_position != -1 && leftmost_position != -1) { if(nppGUI._delimiterSelectionOnEntireDocument) { notifyView->execute(SCI_SETCURRENTPOS, rightmost_position); notifyView->execute(SCI_SETANCHOR, leftmost_position + 1); } else { const int line_position = notifyView->execute(SCI_POSITIONFROMLINE, notifyView->getCurrentLineNumber()); notifyView->execute(SCI_SETCURRENTPOS, line_position + rightmost_position); notifyView->execute(SCI_SETANCHOR, line_position + leftmost_position + 1); } } } else if (_isHotspotDblClicked) { int pos = notifyView->execute(SCI_GETCURRENTPOS); notifyView->execute(SCI_SETCURRENTPOS, pos); notifyView->execute(SCI_SETANCHOR, pos); _isHotspotDblClicked = false; } } break; case SCN_UPDATEUI: { NppParameters *nppParam = NppParameters::getInstance(); // replacement for obsolete custom SCN_SCROLLED if (notification->updated & SC_UPDATE_V_SCROLL) { int urlAction = (NppParameters::getInstance())->getNppGUI()._styleURL; if ((urlAction == 1) || (urlAction == 2)) addHotSpot(); } // if it's searching/replacing, then do nothing if (nppParam->_isFindReplacing) break; if (notification->nmhdr.hwndFrom != _pEditView->getHSelf()) break; braceMatch(); NppGUI & nppGui = (NppGUI &)nppParam->getNppGUI(); if (nppGui._enableTagsMatchHilite) { XmlMatchedTagsHighlighter xmlTagMatchHiliter(_pEditView); xmlTagMatchHiliter.tagMatch(nppGui._enableTagAttrsHilite); } if (nppGui._enableSmartHilite) { if (nppGui._disableSmartHiliteTmp) nppGui._disableSmartHiliteTmp = false; else _smartHighlighter.highlightView(notifyView); } updateStatusBar(); AutoCompletion * autoC = isFromPrimary?&_autoCompleteMain:&_autoCompleteSub; autoC->update(0); break; } case TTN_GETDISPINFO: { try { LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)notification; //Joce's fix lpttt->hinst = NULL; POINT p; ::GetCursorPos(&p); ::ScreenToClient(_pPublicInterface->getHSelf(), &p); HWND hWin = ::RealChildWindowFromPoint(_pPublicInterface->getHSelf(), p); const int tipMaxLen = 1024; static TCHAR docTip[tipMaxLen]; docTip[0] = '\0'; generic_string tipTmp(TEXT("")); int id = int(lpttt->hdr.idFrom); if (hWin == _rebarTop.getHSelf()) { getNameStrFromCmd(id, tipTmp); if (tipTmp.length() >= 80) return FALSE; lstrcpy(lpttt->szText, tipTmp.c_str()); return TRUE; } else if (hWin == _mainDocTab.getHSelf()) { BufferID idd = _mainDocTab.getBufferByIndex(id); Buffer * buf = MainFileManager->getBufferByID(idd); tipTmp = buf->getFullPathName(); if (tipTmp.length() >= tipMaxLen) return FALSE; lstrcpy(docTip, tipTmp.c_str()); lpttt->lpszText = docTip; return TRUE; } else if (hWin == _subDocTab.getHSelf()) { BufferID idd = _subDocTab.getBufferByIndex(id); Buffer * buf = MainFileManager->getBufferByID(idd); tipTmp = buf->getFullPathName(); if (tipTmp.length() >= tipMaxLen) return FALSE; lstrcpy(docTip, tipTmp.c_str()); lpttt->lpszText = docTip; return TRUE; } else { return FALSE; } } catch (...) { //printStr(TEXT("ToolTip crash is caught!")); } } break; case SCN_ZOOM: break; case SCN_MACRORECORD: _macro.push_back(recordedMacroStep(notification->message, notification->wParam, notification->lParam, _pEditView->execute(SCI_GETCODEPAGE))); break; case SCN_PAINTED: { //--FLS: ViewMoveAtWrappingDisableFix: Disable wrapping messes up visible lines. Therefore save view position before in IDM_VIEW_WRAP and restore after SCN_PAINTED, as doc. says if (_mainEditView.isWrapRestoreNeeded()) { _mainEditView.restoreCurrentPos(); _mainEditView.setWrapRestoreNeeded(false); } if (_subEditView.isWrapRestoreNeeded()) { _subEditView.restoreCurrentPos(); _subEditView.setWrapRestoreNeeded(false); } notifyView->updateLineNumberWidth(); if (_syncInfo.doSync()) doSynScorll(HWND(notification->nmhdr.hwndFrom)); NppParameters *nppParam = NppParameters::getInstance(); // if it's searching/replacing, then do nothing if ((_linkTriggered && !nppParam->_isFindReplacing) || notification->wParam == LINKTRIGGERED) { int urlAction = (NppParameters::getInstance())->getNppGUI()._styleURL; if ((urlAction == 1) || (urlAction == 2)) addHotSpot(); _linkTriggered = false; } if (_pDocMap) { _pDocMap->wrapMap(); _pDocMap->scrollMap(); } break; } case SCN_HOTSPOTDOUBLECLICK : { notifyView->execute(SCI_SETWORDCHARS, 0, (LPARAM)"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-+.,:?&@=/%#()"); int pos = notifyView->execute(SCI_GETCURRENTPOS); int startPos = static_cast<int>(notifyView->execute(SCI_WORDSTARTPOSITION, pos, false)); int endPos = static_cast<int>(notifyView->execute(SCI_WORDENDPOSITION, pos, false)); notifyView->execute(SCI_SETTARGETSTART, startPos); notifyView->execute(SCI_SETTARGETEND, endPos); int posFound = notifyView->execute(SCI_SEARCHINTARGET, strlen(URL_REG_EXPR), (LPARAM)URL_REG_EXPR); if (posFound != -2) { if (posFound != -1) { startPos = int(notifyView->execute(SCI_GETTARGETSTART)); endPos = int(notifyView->execute(SCI_GETTARGETEND)); } // Prevent buffer overflow in getGenericText(). if(endPos - startPos > 2*MAX_PATH) endPos = startPos + 2*MAX_PATH; TCHAR currentWord[2*MAX_PATH]; notifyView->getGenericText(currentWord, MAX_PATH*2, startPos, endPos); // This treatment would fail on some valid URLs where there's actually supposed to be a comma or parenthesis at the end. int lastCharIndex = _tcsnlen(currentWord, MAX_PATH*2) - 1; if(lastCharIndex >= 0 && (currentWord[lastCharIndex] == ',' || currentWord[lastCharIndex] == ')' || currentWord[lastCharIndex] == '(')) currentWord[lastCharIndex] = '\0'; ::ShellExecute(_pPublicInterface->getHSelf(), TEXT("open"), currentWord, NULL, NULL, SW_SHOW); _isHotspotDblClicked = true; notifyView->execute(SCI_SETCHARSDEFAULT); } break; } case SCN_NEEDSHOWN : { int begin = notifyView->execute(SCI_LINEFROMPOSITION, notification->position); int end = notifyView->execute(SCI_LINEFROMPOSITION, notification->position + notification->length); int firstLine = begin < end ? begin : end; int lastLine = begin > end ? begin : end; for (int line = firstLine; line <= lastLine; ++line) { notifyView->execute(SCI_ENSUREVISIBLE, line, 0); } break; } case SCN_CALLTIPCLICK: { AutoCompletion * autoC = isFromPrimary?&_autoCompleteMain:&_autoCompleteSub; autoC->callTipClick(notification->position); break; } case RBN_HEIGHTCHANGE: { SendMessage(_pPublicInterface->getHSelf(), WM_SIZE, 0, 0); break; } case RBN_CHEVRONPUSHED: { NMREBARCHEVRON * lpnm = (NMREBARCHEVRON*) notification; ReBar * notifRebar = &_rebarTop; if (_rebarBottom.getHSelf() == lpnm->hdr.hwndFrom) notifRebar = &_rebarBottom; //If N++ ID, use proper object switch(lpnm->wID) { case REBAR_BAR_TOOLBAR: { POINT pt; pt.x = lpnm->rc.left; pt.y = lpnm->rc.bottom; ClientToScreen(notifRebar->getHSelf(), &pt); _toolBar.doPopop(pt); return TRUE; break; } } //Else forward notification to window of rebarband REBARBANDINFO rbBand; ZeroMemory(&rbBand, REBARBAND_SIZE); rbBand.cbSize = REBARBAND_SIZE; rbBand.fMask = RBBIM_CHILD; ::SendMessage(notifRebar->getHSelf(), RB_GETBANDINFO, lpnm->uBand, (LPARAM)&rbBand); ::SendMessage(rbBand.hwndChild, WM_NOTIFY, 0, (LPARAM)lpnm); break; } default : break; } return FALSE; }
BOOL CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG : { initBabyGrid(); initTabs(); fillOutBabyGrid(); _babygrid.display(); goToCenter(); return TRUE; } case WM_NOTIFY: { NMHDR nmh = *((NMHDR*)lParam); if (nmh.hwndFrom == _hTabCtrl) { if (nmh.code == TCN_SELCHANGE) { int index = TabCtrl_GetCurSel(_hTabCtrl); switch (index) { case 0: _currentState = STATE_MENU; break; case 1: _currentState = STATE_MACRO; break; case 2: _currentState = STATE_USER; break; case 3: _currentState = STATE_PLUGIN; break; case 4: _currentState = STATE_SCINTILLA; break; } fillOutBabyGrid(); } } break; } case WM_COMMAND : { switch (LOWORD(wParam)) { case IDCANCEL : { ::EndDialog(_hSelf, -1); return TRUE; } case IDOK : { ::EndDialog(_hSelf, 0); return TRUE; } case IDM_BABYGRID_MODIFY : { NppParameters *nppParam = NppParameters::getInstance(); int row = _babygrid.getSelectedRow(); switch(_currentState) { case STATE_MENU: { //Get CommandShortcut corresponding to row vector<CommandShortcut> & shortcuts = nppParam->getUserShortcuts(); CommandShortcut csc = shortcuts[row - 1], prevcsc = shortcuts[row - 1]; csc.init(_hInst, _hSelf); if (csc.doDialog() != -1 && prevcsc != csc) { //shortcut was altered nppParam->addUserModifiedIndex(row-1); shortcuts[row - 1] = csc; _babygrid.setText(row, 2, csc.toString().c_str()); //Notify current Accelerator class to update everything nppParam->getAccelerator()->updateShortcuts(); } break; } case STATE_MACRO: { //Get MacroShortcut corresponding to row vector<MacroShortcut> & shortcuts = nppParam->getMacroList(); MacroShortcut msc = shortcuts[row - 1], prevmsc = shortcuts[row - 1]; msc.init(_hInst, _hSelf); if (msc.doDialog() != -1 && prevmsc != msc) { //shortcut was altered shortcuts[row - 1] = msc; _babygrid.setText(row, 1, msc.getName()); _babygrid.setText(row, 2, msc.toString().c_str()); //Notify current Accelerator class to update everything nppParam->getAccelerator()->updateShortcuts(); } break; } case STATE_USER: { //Get UserCommand corresponding to row vector<UserCommand> & shortcuts = nppParam->getUserCommandList(); UserCommand ucmd = shortcuts[row - 1], prevucmd = shortcuts[row - 1]; ucmd.init(_hInst, _hSelf); prevucmd = ucmd; if (ucmd.doDialog() != -1 && prevucmd != ucmd) { //shortcut was altered shortcuts[row - 1] = ucmd; _babygrid.setText(row, 1, ucmd.getName()); _babygrid.setText(row, 2, ucmd.toString().c_str()); //Notify current Accelerator class to update everything nppParam->getAccelerator()->updateShortcuts(); } break; } case STATE_PLUGIN: { //Get PluginCmdShortcut corresponding to row vector<PluginCmdShortcut> & shortcuts = nppParam->getPluginCommandList(); PluginCmdShortcut pcsc = shortcuts[row - 1], prevpcsc = shortcuts[row - 1]; pcsc.init(_hInst, _hSelf); prevpcsc = pcsc; if (pcsc.doDialog() != -1 && prevpcsc != pcsc) { //shortcut was altered nppParam->addPluginModifiedIndex(row-1); shortcuts[row - 1] = pcsc; _babygrid.setText(row, 2, pcsc.toString().c_str()); //Notify current Accelerator class to update everything nppParam->getAccelerator()->updateShortcuts(); unsigned long cmdID = pcsc.getID(); ShortcutKey shortcut; shortcut._isAlt = pcsc.getKeyCombo()._isAlt; shortcut._isCtrl = pcsc.getKeyCombo()._isCtrl; shortcut._isShift = pcsc.getKeyCombo()._isShift; shortcut._key = pcsc.getKeyCombo()._key; ::SendMessage(_hParent, NPPM_INTERNAL_PLUGINSHORTCUTMOTIFIED, cmdID, (LPARAM)&shortcut); } break; } case STATE_SCINTILLA: { //Get ScintillaKeyMap corresponding to row vector<ScintillaKeyMap> & shortcuts = nppParam->getScintillaKeyList(); ScintillaKeyMap skm = shortcuts[row - 1], prevskm = shortcuts[row-1]; skm.init(_hInst, _hSelf); if (skm.doDialog() != -1 && prevskm != skm) { //shortcut was altered nppParam->addScintillaModifiedIndex(row-1); shortcuts[row-1] = skm; _babygrid.setText(row, 2, skm.toString().c_str()); //Notify current Accelerator class to update key nppParam->getScintillaAccelerator()->updateKeys(); } break; } } return TRUE; } case IDM_BABYGRID_DELETE : { NppParameters *nppParam = NppParameters::getInstance(); if (::MessageBox(_hSelf, TEXT("Are you sure you want to delete this shortcut?"), TEXT("Are you sure?"), MB_OKCANCEL) == IDOK) { const int row = _babygrid.getSelectedRow(); int shortcutIndex = row-1; DWORD cmdID = 0; // Menu data size_t posBase = 0; size_t nbElem = 0; HMENU hMenu = NULL; int modifCmd = IDM_SETTING_SHORTCUT_MAPPER_RUN; switch(_currentState) { case STATE_MENU: case STATE_PLUGIN: case STATE_SCINTILLA: { return FALSE; //this is bad } case STATE_MACRO: { vector<MacroShortcut> & theMacros = nppParam->getMacroList(); vector<MacroShortcut>::iterator it = theMacros.begin(); cmdID = theMacros[shortcutIndex].getID(); theMacros.erase(it + shortcutIndex); fillOutBabyGrid(); // preparing to remove from menu posBase = 6; nbElem = theMacros.size(); hMenu = ::GetSubMenu((HMENU)::SendMessage(_hParent, NPPM_INTERNAL_GETMENU, 0, 0), MENUINDEX_MACRO); modifCmd = IDM_SETTING_SHORTCUT_MAPPER_MACRO; for (size_t i = shortcutIndex ; i < nbElem ; i++) //lower the IDs of the remaining items so there are no gaps { MacroShortcut ms = theMacros[i]; ms.setID(ms.getID() - 1); //shift all IDs theMacros[i] = ms; } break; } case STATE_USER: { vector<UserCommand> & theUserCmds = nppParam->getUserCommandList(); vector<UserCommand>::iterator it = theUserCmds.begin(); cmdID = theUserCmds[shortcutIndex].getID(); theUserCmds.erase(it + shortcutIndex); fillOutBabyGrid(); // preparing to remove from menu posBase = 2; nbElem = theUserCmds.size(); hMenu = ::GetSubMenu((HMENU)::SendMessage(_hParent, NPPM_INTERNAL_GETMENU, 0, 0), MENUINDEX_RUN); modifCmd = IDM_SETTING_SHORTCUT_MAPPER_RUN; for (size_t i = shortcutIndex ; i < nbElem ; i++) //lower the IDs of the remaining items so there are no gaps { UserCommand uc = theUserCmds[i]; uc.setID(uc.getID() - 1); //shift all IDs theUserCmds[i] = uc; } break; } } // updateShortcuts() will update all menu item - the menu items will be shifted nppParam->getAccelerator()->updateShortcuts(); // All menu items are shifted up. So we delete the last item ::RemoveMenu(hMenu, posBase + nbElem - 1, MF_BYPOSITION); if (nbElem == 0) { ::RemoveMenu(hMenu, modifCmd, MF_BYCOMMAND); //remove separator ::RemoveMenu(hMenu, posBase-1, MF_BYPOSITION); ::RemoveMenu(hMenu, posBase-1, MF_BYPOSITION); } } return TRUE; } case IDD_BABYGRID_ID1: { if(HIWORD(wParam) == BGN_CELLDBCLICKED) //a cell was clicked in the properties grid { return ::SendMessage(_hSelf, WM_COMMAND, IDM_BABYGRID_MODIFY, LOWORD(lParam)); } else if(HIWORD(wParam) == BGN_CELLRCLICKED) //a cell was clicked in the properties grid { POINT p; ::GetCursorPos(&p); if (!_rightClickMenu.isCreated()) { vector<MenuItemUnit> itemUnitArray; itemUnitArray.push_back(MenuItemUnit(IDM_BABYGRID_MODIFY, TEXT("Modify"))); itemUnitArray.push_back(MenuItemUnit(IDM_BABYGRID_DELETE, TEXT("Delete"))); _rightClickMenu.create(_hSelf, itemUnitArray); } switch(_currentState) { case STATE_MACRO: case STATE_USER: { _rightClickMenu.enableItem(IDM_BABYGRID_DELETE, true); break; } case STATE_MENU: case STATE_PLUGIN: case STATE_SCINTILLA: { _rightClickMenu.enableItem(IDM_BABYGRID_DELETE, false); break; } } _rightClickMenu.display(p); return TRUE; } } } } default: return FALSE; } return FALSE; }
BOOL CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG : { initTabs(); initList(); populateShortCuts(); goToCenter(); GetWindowRect(_hSelf,&default_sm_size); AnchorInit(_hSelf,ShortcutAnchors,sizeof(ShortcutAnchors)/sizeof(CONTROL_ANCHOR)); RestoreWinRelPosition(_hParent,_hSelf,&WinRelPos); return TRUE; } case WM_DESTROY: SaveWinRelPosition(_hParent,_hSelf,&WinRelPos); break; case WM_SIZE: AnchorResize(_hSelf,ShortcutAnchors,sizeof(ShortcutAnchors)/sizeof(CONTROL_ANCHOR)); break; case WM_SIZING: return ClampMinWindowSize(&default_sm_size,wParam,(RECT*)lParam); break; case WM_NOTIFY: { NMHDR nmh = *((NMHDR*)lParam); if (nmh.hwndFrom == _hTabCtrl) { if (nmh.code == TCN_SELCHANGE) { int index = TabCtrl_GetCurSel(_hTabCtrl); switch (index) { case 0: _currentState = STATE_MENU; break; case 1: _currentState = STATE_MACRO; break; case 2: _currentState = STATE_USER; break; case 3: _currentState = STATE_PLUGIN; break; case 4: _currentState = STATE_SCINTILLA; break; } populateShortCuts(); } } else if(nmh.hwndFrom==hlistview){ switch(nmh.code){ case NM_DBLCLK: return ::SendMessage(_hSelf, WM_COMMAND, IDC_SHORTCUT_MODIFY, LOWORD(lParam)); case NM_RCLICK: { POINT p; ::GetCursorPos(&p); if (!_rightClickMenu.isCreated()) { vector<MenuItemUnit> itemUnitArray; itemUnitArray.push_back(MenuItemUnit(IDC_SHORTCUT_MODIFY, TEXT("Modify"))); itemUnitArray.push_back(MenuItemUnit(IDC_SHORTCUT_DISABLE, TEXT("Disable"))); itemUnitArray.push_back(MenuItemUnit(0, 0)); itemUnitArray.push_back(MenuItemUnit(IDC_SHORTCUT_DELETE, TEXT("Delete"))); _rightClickMenu.create(_hSelf, itemUnitArray); } switch(_currentState) { case STATE_MACRO: case STATE_USER: { _rightClickMenu.enableItem(IDC_SHORTCUT_DELETE, true); break; } case STATE_MENU: case STATE_PLUGIN: case STATE_SCINTILLA: { _rightClickMenu.enableItem(IDC_SHORTCUT_DELETE, false); break; } } _rightClickMenu.display(p); return TRUE; } } } break; } case WM_COMMAND : { switch (LOWORD(wParam)) { case IDCANCEL : { ::EndDialog(_hSelf, -1); return TRUE; } case IDOK : { if(GetFocus()==hlistview) return ::SendMessage(_hSelf, WM_COMMAND, IDC_SHORTCUT_MODIFY, LOWORD(lParam)); else ::EndDialog(_hSelf, 0); return TRUE; } case IDC_SHORTCUT_FILTER2: case IDC_SHORTCUT_FILTER1: if(HIWORD(wParam)==EN_CHANGE) populateShortCuts(); break; case IDC_SHORTCUT_DISABLE: { int sel=0; sel=disable_selected(FALSE); if(sel!=0){ if(IDOK==MessageBox(_hSelf,TEXT("Ok to disable selected shortcuts?"),TEXT("Warning!"),MB_OKCANCEL|MB_SYSTEMMODAL)){ disable_selected(TRUE); populateShortCuts(); } } } break; case IDC_SHORTCUT_MODIFY : { NppParameters *nppParam = NppParameters::getInstance(); int index; int selected_row=getselectedrow(); if(selected_row<0) break; index=getitemindex(selected_row); switch(_currentState) { case STATE_MENU: { //Get CommandShortcut corresponding to index vector<CommandShortcut> & shortcuts = nppParam->getUserShortcuts(); CommandShortcut csc = shortcuts[index], prevcsc = shortcuts[index]; csc.init(_hInst, _hSelf); csc.set_shortcut_info(_currentState,index); if (csc.doDialog() != -1 && prevcsc != csc) { //shortcut was altered generic_string keys=csc.toString(); nppParam->addUserModifiedIndex(index); shortcuts[index] = csc; ListView_SetItemText(hlistview,selected_row,2,(LPWSTR)keys.c_str()); update_col_width(keys.c_str(),2); //Notify current Accelerator class to update everything nppParam->getAccelerator()->updateShortcuts(); TCHAR str[255]; if(0<check_in_use(_currentState,index,&csc.getKeyCombo(),nppParam,str,sizeof(str)/sizeof(TCHAR))) MessageBox(_hSelf,str,L"Duplicates found",MB_OK); } break; } case STATE_MACRO: { //Get MacroShortcut corresponding to index vector<MacroShortcut> & shortcuts = nppParam->getMacroList(); MacroShortcut msc = shortcuts[index], prevmsc = shortcuts[index]; msc.init(_hInst, _hSelf); msc.set_shortcut_info(_currentState,index); if (msc.doDialog() != -1 && prevmsc != msc) { //shortcut was altered generic_string name=msc.getName(); generic_string keys=msc.toString(); shortcuts[index] = msc; ListView_SetItemText(hlistview,selected_row,1,(LPWSTR)name.c_str()); ListView_SetItemText(hlistview,selected_row,2,(LPWSTR)keys.c_str()); update_col_width(keys.c_str(),2); //Notify current Accelerator class to update everything nppParam->getAccelerator()->updateShortcuts(); TCHAR str[255]; if(0<check_in_use(_currentState,index,&msc.getKeyCombo(),nppParam,str,sizeof(str)/sizeof(TCHAR))) MessageBox(_hSelf,str,L"Duplicates found",MB_OK); } break; } case STATE_USER: { //Get UserCommand corresponding to index vector<UserCommand> & shortcuts = nppParam->getUserCommandList(); UserCommand ucmd = shortcuts[index], prevucmd = shortcuts[index]; ucmd.init(_hInst, _hSelf); ucmd.set_shortcut_info(_currentState,index); prevucmd = ucmd; if (ucmd.doDialog() != -1 && prevucmd != ucmd) { //shortcut was altered generic_string name=ucmd.getName(); generic_string keys=ucmd.toString(); shortcuts[index] = ucmd; ListView_SetItemText(hlistview,selected_row,1,(LPWSTR)name.c_str()); ListView_SetItemText(hlistview,selected_row,2,(LPWSTR)keys.c_str()); update_col_width(name.c_str(),1); update_col_width(keys.c_str(),2); //Notify current Accelerator class to update everything nppParam->getAccelerator()->updateShortcuts(); TCHAR str[255]; if(0<check_in_use(_currentState,index,&ucmd.getKeyCombo(),nppParam,str,sizeof(str)/sizeof(TCHAR))) MessageBox(_hSelf,str,L"Duplicates found",MB_OK); } break; } case STATE_PLUGIN: { //Get PluginCmdShortcut corresponding to index vector<PluginCmdShortcut> & shortcuts = nppParam->getPluginCommandList(); if(shortcuts.empty()) break; PluginCmdShortcut pcsc = shortcuts[index], prevpcsc = shortcuts[index]; pcsc.init(_hInst, _hSelf); pcsc.set_shortcut_info(_currentState,index); prevpcsc = pcsc; if (pcsc.doDialog() != -1 && prevpcsc != pcsc) { //shortcut was altered nppParam->addPluginModifiedIndex(index); generic_string keys=pcsc.toString(); shortcuts[index] = pcsc; ListView_SetItemText(hlistview,selected_row,2,(LPWSTR)keys.c_str()); update_col_width(keys.c_str(),2); //Notify current Accelerator class to update everything nppParam->getAccelerator()->updateShortcuts(); TCHAR str[255]; if(0<check_in_use(_currentState,index,&pcsc.getKeyCombo(),nppParam,str,sizeof(str)/sizeof(TCHAR))) MessageBox(_hSelf,str,L"Duplicates found",MB_OK); unsigned long cmdID = pcsc.getID(); ShortcutKey shortcut; shortcut._isAlt = pcsc.getKeyCombo()._isAlt; shortcut._isCtrl = pcsc.getKeyCombo()._isCtrl; shortcut._isShift = pcsc.getKeyCombo()._isShift; shortcut._key = pcsc.getKeyCombo()._key; ::SendMessage(_hParent, NPPM_INTERNAL_PLUGINSHORTCUTMOTIFIED, cmdID, (LPARAM)&shortcut); } break; } case STATE_SCINTILLA: { //Get ScintillaKeyMap corresponding to index vector<ScintillaKeyMap> & shortcuts = nppParam->getScintillaKeyList(); ScintillaKeyMap skm = shortcuts[index], prevskm = shortcuts[index]; skm.init(_hInst, _hSelf); skm.set_shortcut_info(_currentState,index); if (skm.doDialog() != -1 && prevskm != skm) { //shortcut was altered nppParam->addScintillaModifiedIndex(index); shortcuts[index] = skm; int i,max; TCHAR str[40]={0}; max=skm.getSize(); for(i=0;i<max;i++){ generic_string keys=skm.toString(i); _sntprintf_s(str,sizeof(str)/sizeof(TCHAR),_TRUNCATE,L"%s%s%c",str,keys.c_str(),i<(max-1)?L';':L''); } ListView_SetItemText(hlistview,selected_row,2,(LPWSTR)str); update_col_width(str,2); if(max>0){ TCHAR str[255]; KeyCombo skmkc=skm.getKeyComboByIndex(0); if(0<check_in_use(_currentState,index,&skmkc,nppParam,str,sizeof(str)/sizeof(TCHAR))) MessageBox(_hSelf,str,L"Duplicates found",MB_OK); } //Notify current Accelerator class to update key nppParam->getScintillaAccelerator()->updateKeys(); } break; } } return TRUE; } case IDC_SHORTCUT_DELETE : { NppParameters *nppParam = NppParameters::getInstance(); int index,selected_row=getselectedrow(); TCHAR str[255]={0},msg[255]={0}; if(selected_row<0) break; index=getitemindex(selected_row); ListView_GetItemText(hlistview,selected_row,1,str,sizeof(str)/sizeof(TCHAR)); _sntprintf_s(msg,sizeof(msg)/sizeof(TCHAR),_TRUNCATE, TEXT("%s\r\n%s"), TEXT("Are you sure you want to delete this shortcut?"), str); if (::MessageBox(_hSelf, msg, TEXT("Are you sure?"), MB_OKCANCEL) == IDOK) { int shortcutIndex = index; DWORD cmdID = 0; // Menu data size_t posBase = 0; size_t nbElem = 0; HMENU hMenu = NULL; int modifCmd = IDM_SETTING_SHORTCUT_MAPPER_RUN; switch(_currentState) { case STATE_MENU: case STATE_PLUGIN: case STATE_SCINTILLA: { return FALSE; //this is bad } case STATE_MACRO: { vector<MacroShortcut> & theMacros = nppParam->getMacroList(); vector<MacroShortcut>::iterator it = theMacros.begin(); cmdID = theMacros[shortcutIndex].getID(); theMacros.erase(it + shortcutIndex); populateShortCuts(); // preparing to remove from menu posBase = 6; nbElem = theMacros.size(); hMenu = ::GetSubMenu((HMENU)::SendMessage(_hParent, NPPM_INTERNAL_GETMENU, 0, 0), MENUINDEX_MACRO); modifCmd = IDM_SETTING_SHORTCUT_MAPPER_MACRO; for (size_t i = shortcutIndex ; i < nbElem ; i++) //lower the IDs of the remaining items so there are no gaps { MacroShortcut ms = theMacros[i]; ms.setID(ms.getID() - 1); //shift all IDs theMacros[i] = ms; } break; } case STATE_USER: { vector<UserCommand> & theUserCmds = nppParam->getUserCommandList(); vector<UserCommand>::iterator it = theUserCmds.begin(); cmdID = theUserCmds[shortcutIndex].getID(); theUserCmds.erase(it + shortcutIndex); populateShortCuts(); // preparing to remove from menu posBase = 2; nbElem = theUserCmds.size(); hMenu = ::GetSubMenu((HMENU)::SendMessage(_hParent, NPPM_INTERNAL_GETMENU, 0, 0), MENUINDEX_RUN); modifCmd = IDM_SETTING_SHORTCUT_MAPPER_RUN; for (size_t i = shortcutIndex ; i < nbElem ; i++) //lower the IDs of the remaining items so there are no gaps { UserCommand uc = theUserCmds[i]; uc.setID(uc.getID() - 1); //shift all IDs theUserCmds[i] = uc; } break; } } // updateShortcuts() will update all menu item - the menu items will be shifted nppParam->getAccelerator()->updateShortcuts(); // All menu items are shifted up. So we delete the last item ::RemoveMenu(hMenu, posBase + nbElem, MF_BYPOSITION); if (nbElem == 0) { ::RemoveMenu(hMenu, modifCmd, MF_BYCOMMAND); //remove separator ::RemoveMenu(hMenu, posBase-1, MF_BYPOSITION); ::RemoveMenu(hMenu, posBase-1, MF_BYPOSITION); } } return TRUE; } } } default: return FALSE; } return FALSE; }