void ScintillaAccelerator::updateMenuItemByID(ScintillaKeyMap skm, int id) 
{
	const int commandSize = 64;
	TCHAR cmdName[commandSize];
	::GetMenuString(_hAccelMenu, id, cmdName, commandSize, MF_BYCOMMAND);
	int i = 0;
	while(cmdName[i] != 0)
	{
		if (cmdName[i] == '\t')
		{
			cmdName[i] = 0;
			break;
		}
		++i;
	}
	generic_string menuItem = cmdName;
	if (skm.isEnabled())
	{
		menuItem += TEXT("\t");
		//menuItem += TEXT("Sc:");	//sc: scintilla shortcut
		menuItem += skm.toString();
	}
	::ModifyMenu(_hAccelMenu, id, MF_BYCOMMAND, id, menuItem.c_str());
	::DrawMenuBar(_hMenuParent);
}
void ScintillaAccelerator::updateKeys() 
{
	NppParameters *pNppParam = NppParameters::getInstance();
	vector<ScintillaKeyMap> & map = pNppParam->getScintillaKeyList();
	size_t mapSize = map.size();
	size_t index;

	for(int i = 0; i < _nrScintillas; ++i)
	{
		::SendMessage(_vScintillas[i], SCI_CLEARALLCMDKEYS, 0, 0);
		for(int32_t j = static_cast<int32_t>(mapSize) - 1; j >= 0; j--) //reverse order, top of the list has highest priority
		{	
			ScintillaKeyMap skm = map[j];
			if (skm.isEnabled()) 
			{		//no validating, scintilla accepts more keys
				size_t size = skm.getSize();
				for(index = 0; index < size; ++index)
					::SendMessage(_vScintillas[i], SCI_ASSIGNCMDKEY, skm.toKeyDef(index), skm.getScintillaKeyID());
			}
			if (skm.getMenuCmdID() != 0) 
			{
				updateMenuItemByID(skm, skm.getMenuCmdID());
			}
			if (j == 0)	//j is unsigned, so default method doesnt work
				break;
		}
	}
}
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;
}
INT_PTR 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_DESTROY:
		{
			for (const HFONT & hFont : _hGridFonts)
				::DeleteObject(hFont);
			_hGridFonts.clear();
			_hGridFonts.shrink_to_fit();
			break;
		}

		case WM_NOTIFY: {
			NMHDR nmh = *((NMHDR*)lParam);
			if (nmh.hwndFrom == _hTabCtrl) {
				if (nmh.code == TCN_SELCHANGE) {
					//save the current view
					_lastHomeRow[_currentState] = _babygrid.getHomeRow();
					_lastCursorRow[_currentState] = _babygrid.getSelectedRow();
					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 NPPM_INTERNAL_FINDKEYCONFLICTS:
		{
			if (not wParam || not lParam)
				break;

			generic_string conflictInfo;

			const bool isConflict = findKeyConflicts(&conflictInfo, *reinterpret_cast<KeyCombo*>(wParam), _babygrid.getSelectedRow() - 1);
			*reinterpret_cast<bool*>(lParam) = isConflict;
			if (isConflict)
				::SendDlgItemMessage(_hSelf, IDC_BABYGRID_INFO, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(conflictInfo.c_str()));
			else
				::SendDlgItemMessage(_hSelf, IDC_BABYGRID_INFO, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(_assignInfo.c_str()));

			return TRUE;
		}

		case WM_COMMAND : 
		{
			switch (LOWORD(wParam))
			{
				case IDCANCEL :
				{
					::EndDialog(_hSelf, -1);
					return TRUE;
				}
				case IDOK :
				{
					::EndDialog(_hSelf, 0);
					return TRUE;
				}

				case IDM_BABYGRID_MODIFY :
				{
					if (_babygrid.getNumberRows() < 1)
						return TRUE;

					NppParameters *nppParam = NppParameters::getInstance();
					int row = _babygrid.getSelectedRow();
					bool isModified = false;

					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;

								//save the current view
								_lastHomeRow[_currentState] = _babygrid.getHomeRow();
								_lastCursorRow[_currentState] = _babygrid.getSelectedRow();
								fillOutBabyGrid();

								isModified = true;

								//Notify current Accelerator class to update everything
								nppParam->getAccelerator()->updateShortcuts();
								nppParam->setShortcutDirty();
							}
							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;

								//save the current view
								_lastHomeRow[_currentState] = _babygrid.getHomeRow();
								_lastCursorRow[_currentState] = _babygrid.getSelectedRow();
								fillOutBabyGrid();

								isModified = true;

								//Notify current Accelerator class to update everything
								nppParam->getAccelerator()->updateShortcuts();
								nppParam->setShortcutDirty();
							}
							break; 
						}

						case STATE_USER: 
						{
							//Get UserCommand corresponding to row
							vector<UserCommand> & shortcuts = nppParam->getUserCommandList();
							UserCommand ucmd = shortcuts[row - 1];
							ucmd.init(_hInst, _hSelf);
							UserCommand prevucmd = ucmd;
							if (ucmd.doDialog() != -1 && prevucmd != ucmd)
							{	
								//shortcut was altered
								shortcuts[row - 1] = ucmd;

								//save the current view
								_lastHomeRow[_currentState] = _babygrid.getHomeRow();
								_lastCursorRow[_currentState] = _babygrid.getSelectedRow();
								fillOutBabyGrid();

								isModified = true;

								//Notify current Accelerator class to update everything
								nppParam->getAccelerator()->updateShortcuts();
								nppParam->setShortcutDirty();
							}
							break; 
						}

						case STATE_PLUGIN:
						{
							//Get PluginCmdShortcut corresponding to row
							vector<PluginCmdShortcut> & shortcuts = nppParam->getPluginCommandList();
							PluginCmdShortcut pcsc = shortcuts[row - 1];
							pcsc.init(_hInst, _hSelf);
							PluginCmdShortcut prevpcsc = pcsc;
							if (pcsc.doDialog() != -1 && prevpcsc != pcsc)
							{
								//shortcut was altered
								nppParam->addPluginModifiedIndex(row-1);
								shortcuts[row - 1] = pcsc;

								//save the current view
								_lastHomeRow[_currentState] = _babygrid.getHomeRow();
								_lastCursorRow[_currentState] = _babygrid.getSelectedRow();
								fillOutBabyGrid();

								isModified = true;

								//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, reinterpret_cast<LPARAM>(&shortcut));
								nppParam->setShortcutDirty();
							}
							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;

								//save the current view
								_lastHomeRow[_currentState] = _babygrid.getHomeRow();
								_lastCursorRow[_currentState] = _babygrid.getSelectedRow();
								fillOutBabyGrid();
								_babygrid.updateView();

								isModified = true;

								//Notify current Accelerator class to update key
								nppParam->getScintillaAccelerator()->updateKeys();
								nppParam->setShortcutDirty();
							}
							break; 
						}
					}
					if (not isModified)
						::SendMessage(_hSelf, WM_COMMAND, MAKEWPARAM(IDD_BABYGRID_ID1, BGN_ROWCHANGED), row);
					return TRUE;
				}

				case IDM_BABYGRID_DELETE :
				{
					if (_babygrid.getNumberRows() < 1)
						return TRUE;

					if (::MessageBox(_hSelf, TEXT("Are you sure you want to delete this shortcut?"), TEXT("Are you sure?"), MB_OKCANCEL) == IDOK)
					{
						NppParameters *nppParam = NppParameters::getInstance();
						const int row = _babygrid.getSelectedRow();
						int shortcutIndex = row-1;
						DWORD cmdID = 0;
						
						// Menu data
						int32_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);

								//save the current view
								_lastHomeRow[_currentState] = _babygrid.getHomeRow();
								_lastCursorRow[_currentState] = _babygrid.getSelectedRow();

								const size_t numberRows = _babygrid.getNumberRows();
								if (_lastHomeRow[_currentState] == numberRows)
									--_lastHomeRow[_currentState];
								if (_lastCursorRow[_currentState] == numberRows)
									--_lastCursorRow[_currentState];

								fillOutBabyGrid();
								
								// preparing to remove from menu
								posBase = 6;
								nbElem = theMacros.size();
								HMENU m = reinterpret_cast<HMENU>(::SendMessage(_hParent, NPPM_INTERNAL_GETMENU, 0, 0));
								hMenu = ::GetSubMenu(m, 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);

								//save the current view
								_lastHomeRow[_currentState] = _babygrid.getHomeRow();
								_lastCursorRow[_currentState] = _babygrid.getSelectedRow();

								const size_t numberRows = _babygrid.getNumberRows();
								if (_lastHomeRow[_currentState] == numberRows)
									--_lastHomeRow[_currentState];
								if (_lastCursorRow[_currentState] == numberRows)
									--_lastCursorRow[_currentState];

								fillOutBabyGrid();
							
								// preparing to remove from menu
								posBase = 2;
								nbElem = theUserCmds.size();
								HMENU m = reinterpret_cast<HMENU>(::SendMessage(_hParent, NPPM_INTERNAL_GETMENU, 0, 0));
								hMenu = ::GetSubMenu(m, 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();
						nppParam->setShortcutDirty();

                        // All menu items are shifted up. So we delete the last item
						::RemoveMenu(hMenu, posBase + static_cast<int32_t>(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;
				}

				case IDD_BABYGRID_ID1: 
				{
					switch (HIWORD(wParam))
					{
						case BGN_CELLDBCLICKED: //a cell was clicked in the properties grid
						{
							return ::SendMessage(_hSelf, WM_COMMAND, IDM_BABYGRID_MODIFY, LOWORD(lParam));
						}

						case 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);
							}

							if (_babygrid.getNumberRows() < 1)
							{
								_rightClickMenu.enableItem(IDM_BABYGRID_MODIFY, false);
								_rightClickMenu.enableItem(IDM_BABYGRID_DELETE, false);
							}
							else
							{
								_rightClickMenu.enableItem(IDM_BABYGRID_MODIFY, true);
								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;
						}

						case BGN_DELETECELL: //VK_DELETE
						{
							switch(_currentState) 
							{
								case STATE_MACRO:
								case STATE_USER:
									return ::SendMessage(_hSelf, WM_COMMAND, IDM_BABYGRID_DELETE, 0);
							}
							return TRUE;
						}

						case BGN_ROWCHANGED:
						{
							if (_babygrid.getNumberRows() < 1)
								return TRUE;

							NppParameters *nppParam = NppParameters::getInstance();
							const size_t currentIndex = LOWORD(lParam) - 1;
							generic_string conflictInfo;

							switch (_currentState)
							{
								case STATE_MENU:
								{
									vector<CommandShortcut> & vShortcuts = nppParam->getUserShortcuts();
									findKeyConflicts(&conflictInfo, vShortcuts[currentIndex].getKeyCombo(), currentIndex);
									break;
								}
								case STATE_MACRO:
								{
									vector<MacroShortcut> & vShortcuts = nppParam->getMacroList();
									findKeyConflicts(&conflictInfo, vShortcuts[currentIndex].getKeyCombo(), currentIndex);
									break;
								}
								case STATE_USER:
								{
									vector<UserCommand> & vShortcuts = nppParam->getUserCommandList();
									findKeyConflicts(&conflictInfo, vShortcuts[currentIndex].getKeyCombo(), currentIndex);
									break;
								}
								case STATE_PLUGIN:
								{
									vector<PluginCmdShortcut> & vShortcuts = nppParam->getPluginCommandList();
									findKeyConflicts(&conflictInfo, vShortcuts[currentIndex].getKeyCombo(), currentIndex);
									break;
								}
								case STATE_SCINTILLA:
								{
									vector<ScintillaKeyMap> & vShortcuts = nppParam->getScintillaKeyList();
									size_t sciCombos = vShortcuts[currentIndex].getSize();
									for (size_t sciIndex = 0; sciIndex < sciCombos; ++sciIndex)
										findKeyConflicts(&conflictInfo, vShortcuts[currentIndex].getKeyComboByIndex(sciIndex), currentIndex);
									break;
								}
							}

							if (conflictInfo.empty())
								::SendDlgItemMessage(_hSelf, IDC_BABYGRID_INFO, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(_defaultInfo.c_str()));
							else
								::SendDlgItemMessage(_hSelf, IDC_BABYGRID_INFO, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(conflictInfo.c_str()));

							return TRUE;
						}
					} //switch (HIWORD(wParam))
				}
			} //switch (LOWORD(wParam))
		}
		default:
			return FALSE;
	} //switch (message)
	return FALSE;
}
Example #5
0
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;
}
Example #6
0
int ShortcutMapper::disable_selected(int disable)
{
	int i,count,sel=0;
	NppParameters *nppParam = NppParameters::getInstance();
	count=ListView_GetItemCount(hlistview);
	for(i=0;i<count;i++){
		if(ListView_GetItemState(hlistview,i,LVIS_SELECTED)==LVIS_SELECTED){
			int	index=getitemindex(i);
			switch(_currentState) {
			case STATE_MENU:
				{
					vector<CommandShortcut> & shortcuts = nppParam->getUserShortcuts();
					CommandShortcut csc = shortcuts[index];
					if(disable){
						sel+=csc.Disable();
						shortcuts[index]=csc;
					}
					else
						sel+=csc.isEnabled();
				}
				break;
			case STATE_MACRO:
				{
					vector<MacroShortcut> & shortcuts = nppParam->getMacroList();
					MacroShortcut msc = shortcuts[index];
					if(disable){
						sel+=msc.Disable();
						shortcuts[index]=msc;
					}
					else
						sel+=msc.isEnabled();
				}
				break;
			case STATE_USER:
				{
					vector<UserCommand> & shortcuts = nppParam->getUserCommandList();
					UserCommand ucmd = shortcuts[index];
					if(disable){
						sel+=ucmd.Disable();
						shortcuts[index]=ucmd;
					}
					else
						sel+=ucmd.isEnabled();
				}
				break;
			case STATE_PLUGIN:
				{
					vector<PluginCmdShortcut> & shortcuts = nppParam->getPluginCommandList();
					if(shortcuts.empty())
						break;
					PluginCmdShortcut pcsc = shortcuts[index];
					if(disable){
						sel+=pcsc.Disable();
						shortcuts[index]=pcsc;
					}
					else
						sel+=pcsc.isEnabled();
				}
				break;
			case STATE_SCINTILLA:
				{
					vector<ScintillaKeyMap> & shortcuts = nppParam->getScintillaKeyList();
					ScintillaKeyMap skm = shortcuts[index];
					if(disable){
						int j;
						for(j=skm.getSize()-1;j>=0;j--)
							skm.removeKeyComboByIndex(j);
						skm.Disable();
						sel++;
						shortcuts[index]=skm;
					}
					else
						sel+=skm.isEnabled();
				}
				break;
			}
		}
	}
	return sel;
}