From 1abac157993685c4f6345443f6256403526858ad Mon Sep 17 00:00:00 2001 From: A-R-C-A Date: Mon, 11 Jul 2016 23:24:05 +0000 Subject: [PATCH] Enhancement: add conflict detection to Shortcut Mapper Closese #2029 Added a basic conflict detection functionality to the Shortcut Mapper. This includes: * Marking conflicts with a different background color. * Displaying conflict information. * Warning when attempting to assign an already existing short-key. Some more related changes to the Shortcut Mapper: * Fixed some bugs, for instance: 1. Babygrid was shrinking on any attempt to adjust its position to integral rows. 2. Context menu entries were enabled for empty lists. Using them would crash Npp. 3. ... some more minor bug fixes. * Performance enhancements to Babygrid. * Minor UI improvements. * Babygrid is configured dpi aware. --- PowerEditor/src/Notepad_plus.h | 3 + PowerEditor/src/NppBigSwitch.cpp | 24 + PowerEditor/src/WinControls/Grid/BabyGrid.cpp | 239 ++++++-- PowerEditor/src/WinControls/Grid/BabyGrid.h | 6 + .../src/WinControls/Grid/BabyGridWrapper.cpp | 2 +- .../src/WinControls/Grid/BabyGridWrapper.h | 61 ++ .../src/WinControls/Grid/ShortcutMapper.cpp | 556 ++++++++++++++++-- .../src/WinControls/Grid/ShortcutMapper.h | 27 + .../src/WinControls/Grid/ShortcutMapper.rc | 3 +- .../src/WinControls/Grid/ShortcutMapper_rc.h | 1 + .../StaticDialog/RunDlg/RunDlg.cpp | 7 +- .../src/WinControls/shortcut/shortcut.cpp | 42 +- .../src/WinControls/shortcut/shortcut.h | 1 + .../src/WinControls/shortcut/shortcut.rc | 12 +- .../src/WinControls/shortcut/shortcutRc.h | 1 + PowerEditor/src/resource.h | 1 + 16 files changed, 885 insertions(+), 101 deletions(-) diff --git a/PowerEditor/src/Notepad_plus.h b/PowerEditor/src/Notepad_plus.h index c362d7ae..6a74b97d 100644 --- a/PowerEditor/src/Notepad_plus.h +++ b/PowerEditor/src/Notepad_plus.h @@ -376,6 +376,9 @@ private: bool _playingBackMacro = false; RunMacroDlg _runMacroDlg; + // For conflict detection when saving Macros or RunCommands + ShortcutMapper * _pShortcutMapper = nullptr; + // For hotspot bool _linkTriggered = true; bool _isHotspotDblClicked = false; diff --git a/PowerEditor/src/NppBigSwitch.cpp b/PowerEditor/src/NppBigSwitch.cpp index f56a47d2..5179c5ba 100644 --- a/PowerEditor/src/NppBigSwitch.cpp +++ b/PowerEditor/src/NppBigSwitch.cpp @@ -1257,6 +1257,30 @@ LRESULT Notepad_plus::process(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPa return TRUE; } + case NPPM_INTERNAL_FINDKEYCONFLICTS: + { + if (not wParam || not lParam) // Clean up current session + { + if (_pShortcutMapper != nullptr) + { + delete _pShortcutMapper; + _pShortcutMapper = nullptr; + } + return TRUE; + } + + if (_pShortcutMapper == nullptr) // Begin new session + { + _pShortcutMapper = new ShortcutMapper; + if (_pShortcutMapper == nullptr) + break; + } + + *reinterpret_cast(lParam) = _pShortcutMapper->findKeyConflicts(nullptr, *reinterpret_cast(wParam), (size_t)-1); + + return TRUE; + } + case NPPM_INTERNAL_SETCARETWIDTH: { NppGUI & nppGUI = (NppGUI &)pNppParam->getNppGUI(); diff --git a/PowerEditor/src/WinControls/Grid/BabyGrid.cpp b/PowerEditor/src/WinControls/Grid/BabyGrid.cpp index 516d1572..06f225b7 100644 --- a/PowerEditor/src/WinControls/Grid/BabyGrid.cpp +++ b/PowerEditor/src/WinControls/Grid/BabyGrid.cpp @@ -58,6 +58,9 @@ struct _gridhandlestruct COLORREF unprotectcolor; COLORREF textcolor; COLORREF highlightcolor; + COLORREF highlightcolorNoFocus; + COLORREF highlightcolorProtect; + COLORREF highlightcolorProtectNoFocus; COLORREF gridlinecolor; COLORREF highlighttextcolor; BOOL DRAWHIGHLIGHT; @@ -77,7 +80,7 @@ struct _gridhandlestruct BOOL HSCROLL; BOOL VSCROLL; BOOL SHOWINTEGRALROWS; - BOOL SIZING; + //BOOL SIZING; //obsolete BOOL ELLIPSIS; BOOL COLAUTOWIDTH; BOOL COLUMNSIZING; @@ -88,8 +91,9 @@ struct _gridhandlestruct int cursortype; int columnwidths[MAX_COLS+1]; BOOL REMEMBERINTEGRALROWS; - int wannabeheight; - int wannabewidth; + //int wannabeheight; //obsolete + //int wannabewidth; //obsolete + BOOL INITIALCONTENT; } BGHS[MAX_GRIDS]; @@ -361,7 +365,7 @@ void DisplayColumn(HWND hWnd,int SI,int c,int offset,HFONT hfont,HFONT hcolumnhe HFONT holdfont; int r; TCHAR buffer[1000]; - int iDataType,iProtection; + int iDataType,iProtection,iProperty; if(BGHS[SI].columnwidths[c]==0){return;} gdc=GetDC(hWnd); @@ -415,7 +419,6 @@ void DisplayColumn(HWND hWnd,int SI,int c,int offset,HFONT hfont,HFONT hcolumnhe SetCell(&BGcell,r,c); lstrcpy(buffer, TEXT("")); - SendMessage(hWnd,BGM_GETCELLDATA,(WPARAM)&BGcell,(LPARAM)buffer); if(BGHS[SI].COLUMNSNUMBERED) { if(c>0) @@ -429,6 +432,9 @@ void DisplayColumn(HWND hWnd,int SI,int c,int offset,HFONT hfont,HFONT hcolumnhe wsprintf(buffer, TEXT("%c%c"), high,low); } } + else + SendMessage(hWnd,BGM_GETCELLDATA,(WPARAM)&BGcell,(LPARAM)buffer); + rectsave=rect; DrawEdge(gdc,&rect,EDGE_ETCHED,BF_MIDDLE|BF_RECT|BF_ADJUST); DrawTextEx(gdc,buffer,-1,&rect,DT_END_ELLIPSIS|DT_CENTER|DT_WORDBREAK|DT_NOPREFIX,NULL); @@ -462,11 +468,16 @@ void DisplayColumn(HWND hWnd,int SI,int c,int offset,HFONT hfont,HFONT hcolumnhe rectsave=rect; SetCell(&BGcell,r,c); lstrcpy(buffer, TEXT("")); - SendMessage(hWnd,BGM_GETCELLDATA,(WPARAM)&BGcell,(LPARAM)buffer); if((c==0)&&(BGHS[SI].ROWSNUMBERED)) { wsprintf(buffer, TEXT("%d"), r); + iProperty = 2 << 4; // iDataType = NUMERIC } + else + // iProperty will combine (iDataType << 4) and (iProtection & 0xf), + // this will reduce some unnecessary and 'heavy' message calls for getting iDataType and iProtection separately + iProperty = static_cast(SendMessage(hWnd, BGM_GETCELLDATA, (WPARAM)&BGcell, (LPARAM)buffer)); + if(c==0) { DrawEdge(gdc,&rect,EDGE_ETCHED,BF_MIDDLE|BF_RECT|BF_ADJUST); @@ -476,18 +487,25 @@ void DisplayColumn(HWND hWnd,int SI,int c,int offset,HFONT hfont,HFONT hcolumnhe { HBRUSH hbrush,holdbrush; HPEN hpen,holdpen; - iProtection = static_cast(SendMessage(hWnd, BGM_GETPROTECTION, (WPARAM)&BGcell, 0)); + //iProtection = static_cast(SendMessage(hWnd, BGM_GETPROTECTION, (WPARAM)&BGcell, 0)); + iProtection = iProperty & 0xf; if(BGHS[SI].DRAWHIGHLIGHT)//highlight on { if(r==BGHS[SI].cursorrow) { if(BGHS[SI].GRIDHASFOCUS) { - hbrush=CreateSolidBrush(BGHS[SI].highlightcolor); + if(iProtection == 1) + hbrush=CreateSolidBrush(BGHS[SI].highlightcolorProtect); + else + hbrush=CreateSolidBrush(BGHS[SI].highlightcolor); } else { - hbrush=CreateSolidBrush(RGB(200,200,200)); + if(iProtection == 1) + hbrush=CreateSolidBrush(BGHS[SI].highlightcolorProtectNoFocus); + else + hbrush=CreateSolidBrush(BGHS[SI].highlightcolorNoFocus); } } @@ -527,12 +545,13 @@ void DisplayColumn(HWND hWnd,int SI,int c,int offset,HFONT hfont,HFONT hcolumnhe rect.right -= 2; rect.left += 2; - iDataType = static_cast(SendMessage(hWnd, BGM_GETTYPE, (WPARAM)&BGcell, 0)); + //iDataType = static_cast(SendMessage(hWnd, BGM_GETTYPE, (WPARAM)&BGcell, 0)); + iDataType = iProperty >> 4 & 0xf; if((iDataType < 1)||(iDataType > 5)) { iDataType = 1;//default to alphanumeric data type.. can't happen } - if(c==0){iDataType = 2;} + //if(c==0){iDataType = 2;} if(iDataType == 1)//ALPHA { @@ -1226,13 +1245,16 @@ ATOM RegisterGridClass(HINSTANCE hInstance) BGHS[j].protectcolor = RGB(255,255,255); BGHS[j].unprotectcolor = RGB(255,255,255); BGHS[j].highlightcolor = RGB(0,0,128); + BGHS[j].highlightcolorNoFocus = RGB(200,200,200); + BGHS[j].highlightcolorProtect = RGB(0,0,128); + BGHS[j].highlightcolorProtectNoFocus = RGB(200,200,200); BGHS[j].gridlinecolor = RGB(220,220,220); BGHS[j].highlighttextcolor = RGB(255,255,255); BGHS[j].textcolor = RGB(0,0,0); BGHS[j].titleheight = 0; BGHS[j].EXTENDLASTCOLUMN = TRUE; BGHS[j].SHOWINTEGRALROWS = TRUE; - BGHS[j].SIZING = FALSE; + //BGHS[j].SIZING = FALSE; //obsolete BGHS[j].ELLIPSIS = TRUE; BGHS[j].COLAUTOWIDTH = FALSE; BGHS[j].COLUMNSIZING = FALSE; @@ -1240,6 +1262,7 @@ ATOM RegisterGridClass(HINSTANCE hInstance) BGHS[j].cursortype = 0; BGHS[j].hcolumnheadingfont = NULL; BGHS[j].htitlefont = NULL; + BGHS[j].INITIALCONTENT = FALSE; lstrcpy(BGHS[j].editstring, TEXT("")); for(int k = 0 ; k < MAX_COLS ; k++) @@ -1268,11 +1291,12 @@ ATOM RegisterGridClass(HINSTANCE hInstance) } -void SizeGrid(HWND hWnd,int SI) +void SizeGrid(HWND hWnd,int /*SI*/) { - SendMessage(hWnd,WM_SIZE,SIZE_MAXIMIZED,MAKELPARAM(BGHS[SI].wannabewidth,BGHS[SI].wannabeheight)); - SendMessage(hWnd,WM_SIZE,SIZE_MAXIMIZED,MAKELPARAM(BGHS[SI].wannabewidth,BGHS[SI].wannabeheight)); - + SendMessage(hWnd,WM_SIZE,SIZE_MAXIMIZED,0); + //obsolete + //SendMessage(hWnd,WM_SIZE,SIZE_MAXIMIZED,MAKELPARAM(BGHS[SI].wannabewidth,BGHS[SI].wannabeheight)); + //SendMessage(hWnd,WM_SIZE,SIZE_MAXIMIZED,MAKELPARAM(BGHS[SI].wannabewidth,BGHS[SI].wannabeheight)); } int FindLongestLine(HDC hdc,TCHAR* text,SIZE* size) @@ -1354,7 +1378,8 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) GetClientRect(hWnd, &rt); CalcVisibleCellBoundaries(SelfIndex); //display title - DisplayTitle(hWnd,SelfIndex,BGHS[SelfIndex].htitlefont); + if (BGHS[SelfIndex].titleheight > 0) + DisplayTitle(hWnd,SelfIndex,BGHS[SelfIndex].htitlefont); //display column 0; DisplayColumn(hWnd,SelfIndex,0,0,BGHS[SelfIndex].hfont,BGHS[SelfIndex].hcolumnheadingfont); @@ -1482,6 +1507,27 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) RefreshGrid(hWnd); break; + + case BGM_SETLASTVIEW: + if ((((int)wParam <= BGHS[SelfIndex].rows) && ((int)wParam > 0)) && + (((int)lParam <= BGHS[SelfIndex].rows) && ((int)lParam > 0))) + { + BGHS[SelfIndex].homerow = static_cast(wParam); + BGHS[SelfIndex].homecol = 1; + BGHS[SelfIndex].cursorrow = static_cast(lParam); + BGHS[SelfIndex].cursorcol = 1; + + SetHomeRow(hWnd, SelfIndex, BGHS[SelfIndex].cursorrow, BGHS[SelfIndex].cursorcol); + RefreshGrid(hWnd); + + NotifyRowChanged(hWnd, SelfIndex); + } + break; + + case BGM_SETINITIALCONTENT: + BGHS[SelfIndex].INITIALCONTENT = (BOOL)wParam; + break; + case BGM_SHOWHILIGHT: BGHS[SelfIndex].DRAWHIGHLIGHT = (BOOL)wParam; RefreshGrid(hWnd); @@ -1600,13 +1646,18 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) break; } wsprintf(buffer, TEXT("%05d-%03d"), LPBGcell->row,LPBGcell->col); - //see if that cell is already loaded - FindResult = BinarySearchListBox(BGHS[SelfIndex].hlist1,buffer); - if(FindResult != LB_ERR) - { - //it was found, delete it - SendMessage(BGHS[SelfIndex].hlist1,LB_DELETESTRING,FindResult,0); - } + + if (not BGHS[SelfIndex].INITIALCONTENT) // performance enhancement while adding new data + { + //see if that cell is already loaded + FindResult = BinarySearchListBox(BGHS[SelfIndex].hlist1,buffer); + if(FindResult != LB_ERR) + { + //it was found, delete it + SendMessage(BGHS[SelfIndex].hlist1,LB_DELETESTRING,FindResult,0); + } + } + //now add it lstrcat(buffer, TEXT("|")); lstrcat(buffer,BGHS[SelfIndex].protect); @@ -1658,7 +1709,7 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) if((BGHS[SelfIndex].COLAUTOWIDTH)||(LPBGcell->row == 0)) { HDC hdc; - SIZE size; + SIZE size { 0, 0 }; int required_width; int current_width; int required_height = 30; @@ -1710,7 +1761,7 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) current_height = BGHS[SelfIndex].rowheight; if(required_height > current_height) { - SendMessage(hWnd, BGM_SETROWHEIGHT, /*required_height*/20, 0); + SendMessage(hWnd, BGM_SETROWHEIGHT, required_height, 0); } } @@ -1738,11 +1789,26 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) FindResult = BinarySearchListBox(BGHS[SelfIndex].hlist1,buffer); if(FindResult != LB_ERR) { + //it was found, get it + SendMessage(BGHS[SelfIndex].hlist1,LB_GETTEXT,FindResult,(LPARAM)buffer); + switch (buffer[10]) // no need to call BGM_GETPROTECTION separately for this + { + case 'U': ReturnValue = 0; break; + case 'P': ReturnValue = 1; break; + default : ReturnValue = 0; break; + } + switch (buffer[11]) // no need to call BGM_GETTYPE separately for this + { + case 'A': ReturnValue |= 1 << 4; break; + case 'N': ReturnValue |= 2 << 4; break; + case 'T': ReturnValue |= 3 << 4; break; + case 'F': ReturnValue |= 4 << 4; break; + case 'G': ReturnValue |= 5 << 4; break; + default : ReturnValue |= 1 << 4; break; + } int j,k,c; TCHAR tbuffer[1000]; - //it was found, get it - SendMessage(BGHS[SelfIndex].hlist1,LB_GETTEXT,FindResult,(LPARAM)lParam); - lstrcpy(tbuffer,(TCHAR*)lParam); + lstrcpy(tbuffer,buffer); k=lstrlen(tbuffer); c=0; for(j=13;j_dpiManager.scaleY(30) > 30) + { + WINDOWPLACEMENT wp; + wp.length = sizeof(wp); + + ::GetWindowPlacement(hTab, &wp); + + const int offset = NppParameters::getInstance()->_dpiManager.scaleY(30) - wp.rcNormalPosition.bottom; + wp.rcNormalPosition.bottom += offset; + wp.rcNormalPosition.top += offset + 1; + + ::SetWindowPlacement(hTab, &wp); + } } void ShortcutMapper::getClientRect(RECT & rc) const { Window::getClientRect(rc); - rc.top += NppParameters::getInstance()->_dpiManager.scaleY(40); - rc.bottom -= NppParameters::getInstance()->_dpiManager.scaleY(20); + rc.top += NppParameters::getInstance()->_dpiManager.scaleY(30); + rc.bottom -= NppParameters::getInstance()->_dpiManager.scaleY(108); rc.left += NppParameters::getInstance()->_dpiManager.scaleX(5); - + rc.right -= NppParameters::getInstance()->_dpiManager.scaleX(5); } void ShortcutMapper::translateTab(int index, const TCHAR * newname) { @@ -68,21 +89,46 @@ void ShortcutMapper::translateTab(int index, const TCHAR * newname) { void ShortcutMapper::initBabyGrid() { RECT rect; getClientRect(rect); + + _lastHomeRow.resize(5, 1); + _lastCursorRow.resize(5, 1); + + _hGridFonts.resize(MAX_GRID_FONTS); + _hGridFonts.at(GFONT_HEADER) = ::CreateFont( + NppParameters::getInstance()->_dpiManager.scaleY(18), 0, 0, 0, FW_BOLD, + FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, + TEXT("MS Shell Dlg")); + _hGridFonts.at(GFONT_ROWS) = ::CreateFont( + NppParameters::getInstance()->_dpiManager.scaleY(16), 0, 0, 0, FW_NORMAL, + FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, + TEXT("MS Shell Dlg")); _babygrid.init(_hInst, _hSelf, IDD_BABYGRID_ID1); + + _babygrid.setHeaderFont(_hGridFonts.at(GFONT_HEADER)); + _babygrid.setRowFont(_hGridFonts.at(GFONT_ROWS)); _babygrid.reSizeToWH(rect); _babygrid.hideCursor(); _babygrid.makeColAutoWidth(); + _babygrid.setAutoRow(false); _babygrid.setColsNumbered(false); - _babygrid.setColWidth(0, 30); - _babygrid.setColWidth(1, 250); + _babygrid.setColWidth(0, NppParameters::getInstance()->_dpiManager.scaleX(30)); + _babygrid.setColWidth(1, NppParameters::getInstance()->_dpiManager.scaleX(250)); + _babygrid.setHeaderHeight(NppParameters::getInstance()->_dpiManager.scaleY(21)); + _babygrid.setRowHeight(NppParameters::getInstance()->_dpiManager.scaleY(21)); + + _babygrid.setHighlightColorNoFocus(RGB(200,200,210)); + _babygrid.setProtectColor(RGB(255,130,120)); + _babygrid.setHighlightColorProtect(RGB(244,10,20)); + _babygrid.setHighlightColorProtectNoFocus(RGB(230,194,190)); } void ShortcutMapper::fillOutBabyGrid() { NppParameters *nppParam = NppParameters::getInstance(); _babygrid.clear(); + _babygrid.setInitialContent(true); size_t nrItems = 0; @@ -112,13 +158,22 @@ void ShortcutMapper::fillOutBabyGrid() _babygrid.setText(0, 1, TEXT("Name")); _babygrid.setText(0, 2, TEXT("Shortcut")); + bool isMarker = false; + switch(_currentState) { case STATE_MENU: { vector & cshortcuts = nppParam->getUserShortcuts(); for(size_t i = 0; i < nrItems; ++i) { + if (findKeyConflicts(nullptr, cshortcuts[i].getKeyCombo(), i)) + isMarker = _babygrid.setMarker(true); + _babygrid.setText(i+1, 1, cshortcuts[i].getName()); - _babygrid.setText(i+1, 2, cshortcuts[i].toString().c_str()); + if (cshortcuts[i].isEnabled()) //avoid empty strings for better performance + _babygrid.setText(i+1, 2, cshortcuts[i].toString().c_str()); + + if (isMarker) + isMarker = _babygrid.setMarker(false); } ::EnableWindow(::GetDlgItem(_hSelf, IDM_BABYGRID_MODIFY), true); ::EnableWindow(::GetDlgItem(_hSelf, IDM_BABYGRID_DELETE), false); @@ -127,8 +182,15 @@ void ShortcutMapper::fillOutBabyGrid() vector & cshortcuts = nppParam->getMacroList(); for(size_t i = 0; i < nrItems; ++i) { + if (findKeyConflicts(nullptr, cshortcuts[i].getKeyCombo(), i)) + isMarker = _babygrid.setMarker(true); + _babygrid.setText(i+1, 1, cshortcuts[i].getName()); - _babygrid.setText(i+1, 2, cshortcuts[i].toString().c_str()); + if (cshortcuts[i].isEnabled()) //avoid empty strings for better performance + _babygrid.setText(i+1, 2, cshortcuts[i].toString().c_str()); + + if (isMarker) + isMarker = _babygrid.setMarker(false); } bool shouldBeEnabled = nrItems > 0; ::EnableWindow(::GetDlgItem(_hSelf, IDM_BABYGRID_MODIFY), shouldBeEnabled); @@ -138,8 +200,15 @@ void ShortcutMapper::fillOutBabyGrid() vector & cshortcuts = nppParam->getUserCommandList(); for(size_t i = 0; i < nrItems; ++i) { + if (findKeyConflicts(nullptr, cshortcuts[i].getKeyCombo(), i)) + isMarker = _babygrid.setMarker(true); + _babygrid.setText(i+1, 1, cshortcuts[i].getName()); - _babygrid.setText(i+1, 2, cshortcuts[i].toString().c_str()); + if (cshortcuts[i].isEnabled()) //avoid empty strings for better performance + _babygrid.setText(i+1, 2, cshortcuts[i].toString().c_str()); + + if (isMarker) + isMarker = _babygrid.setMarker(false); } bool shouldBeEnabled = nrItems > 0; ::EnableWindow(::GetDlgItem(_hSelf, IDM_BABYGRID_MODIFY), shouldBeEnabled); @@ -149,8 +218,15 @@ void ShortcutMapper::fillOutBabyGrid() vector & cshortcuts = nppParam->getPluginCommandList(); for(size_t i = 0; i < nrItems; ++i) { + if (findKeyConflicts(nullptr, cshortcuts[i].getKeyCombo(), i)) + isMarker = _babygrid.setMarker(true); + _babygrid.setText(i+1, 1, cshortcuts[i].getName()); - _babygrid.setText(i+1, 2, cshortcuts[i].toString().c_str()); + if (cshortcuts[i].isEnabled()) //avoid empty strings for better performance + _babygrid.setText(i+1, 2, cshortcuts[i].toString().c_str()); + + if (isMarker) + isMarker = _babygrid.setMarker(false); } bool shouldBeEnabled = nrItems > 0; ::EnableWindow(::GetDlgItem(_hSelf, IDM_BABYGRID_MODIFY), shouldBeEnabled); @@ -160,13 +236,37 @@ void ShortcutMapper::fillOutBabyGrid() vector & cshortcuts = nppParam->getScintillaKeyList(); for(size_t i = 0; i < nrItems; ++i) { + if (cshortcuts[i].isEnabled()) + { + size_t sciCombos = cshortcuts[i].getSize(); + for (size_t sciIndex = 0; sciIndex < sciCombos; ++sciIndex) + { + if (findKeyConflicts(nullptr, cshortcuts[i].getKeyComboByIndex(sciIndex), i)) + { + isMarker = _babygrid.setMarker(true); + break; + } + } + } + _babygrid.setText(i+1, 1, cshortcuts[i].getName()); - _babygrid.setText(i+1, 2, cshortcuts[i].toString().c_str()); + if (cshortcuts[i].isEnabled()) //avoid empty strings for better performance + _babygrid.setText(i+1, 2, cshortcuts[i].toString().c_str()); + + if (isMarker) + isMarker = _babygrid.setMarker(false); } ::EnableWindow(::GetDlgItem(_hSelf, IDM_BABYGRID_MODIFY), true); ::EnableWindow(::GetDlgItem(_hSelf, IDM_BABYGRID_DELETE), false); break; } } + if (nrItems > 0) + //restore the last view + _babygrid.setLastView(_lastHomeRow[_currentState], _lastCursorRow[_currentState]); + else + //clear the info area + ::SendDlgItemMessage(_hSelf, IDC_BABYGRID_INFO, WM_SETTEXT, 0, 0); + _babygrid.setInitialContent(false); } INT_PTR CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) @@ -183,10 +283,22 @@ INT_PTR CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM 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: @@ -210,6 +322,23 @@ INT_PTR CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM } break; } + case NPPM_INTERNAL_FINDKEYCONFLICTS: + { + if (not wParam || not lParam) + break; + + generic_string conflictInfo; + + const bool isConflict = findKeyConflicts(&conflictInfo, *reinterpret_cast(wParam), _babygrid.getSelectedRow() - 1); + *reinterpret_cast(lParam) = isConflict; + if (isConflict) + ::SendDlgItemMessage(_hSelf, IDC_BABYGRID_INFO, WM_SETTEXT, 0, (LPARAM)conflictInfo.c_str()); + else + ::SendDlgItemMessage(_hSelf, IDC_BABYGRID_INFO, WM_SETTEXT, 0, (LPARAM)_assignInfo.c_str()); + + return TRUE; + } + case WM_COMMAND : { switch (LOWORD(wParam)) @@ -227,8 +356,12 @@ INT_PTR CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM case IDM_BABYGRID_MODIFY : { + if (_babygrid.getNumberRows() < 1) + return TRUE; + NppParameters *nppParam = NppParameters::getInstance(); int row = _babygrid.getSelectedRow(); + bool isModified = false; switch(_currentState) { @@ -243,7 +376,14 @@ INT_PTR CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM //shortcut was altered nppParam->addUserModifiedIndex(row-1); shortcuts[row - 1] = csc; - _babygrid.setText(row, 2, csc.toString().c_str()); + + //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(); @@ -261,8 +401,13 @@ INT_PTR CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM { //shortcut was altered shortcuts[row - 1] = msc; - _babygrid.setText(row, 1, msc.getName()); - _babygrid.setText(row, 2, msc.toString().c_str()); + + //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(); @@ -282,8 +427,13 @@ INT_PTR CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM { //shortcut was altered shortcuts[row - 1] = ucmd; - _babygrid.setText(row, 1, ucmd.getName()); - _babygrid.setText(row, 2, ucmd.toString().c_str()); + + //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(); @@ -304,7 +454,13 @@ INT_PTR CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM //shortcut was altered nppParam->addPluginModifiedIndex(row-1); shortcuts[row - 1] = pcsc; - _babygrid.setText(row, 2, pcsc.toString().c_str()); + + //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(); @@ -332,7 +488,14 @@ INT_PTR CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM //shortcut was altered nppParam->addScintillaModifiedIndex(row-1); shortcuts[row-1] = skm; - _babygrid.setText(row, 2, skm.toString().c_str()); + + //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(); @@ -341,14 +504,19 @@ INT_PTR CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM break; } } + if (not isModified) + ::SendMessage(_hSelf, WM_COMMAND, MAKEWPARAM(IDD_BABYGRID_ID1, BGN_ROWCHANGED), row); return TRUE; } case IDM_BABYGRID_DELETE : { - NppParameters *nppParam = NppParameters::getInstance(); + 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; @@ -373,6 +541,17 @@ INT_PTR CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM vector::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 @@ -395,6 +574,17 @@ INT_PTR CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM vector::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 @@ -431,42 +621,316 @@ INT_PTR CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM return TRUE; } - case IDD_BABYGRID_ID1: { - if(HIWORD(wParam) == BGN_CELLDBCLICKED) //a cell was clicked in the properties grid + case IDD_BABYGRID_ID1: + { + switch (HIWORD(wParam)) { - 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()) + case BGN_CELLDBCLICKED: //a cell was clicked in the properties grid { - vector itemUnitArray; - itemUnitArray.push_back(MenuItemUnit(IDM_BABYGRID_MODIFY, TEXT("Modify"))); - itemUnitArray.push_back(MenuItemUnit(IDM_BABYGRID_DELETE, TEXT("Delete"))); - _rightClickMenu.create(_hSelf, itemUnitArray); + return ::SendMessage(_hSelf, WM_COMMAND, IDM_BABYGRID_MODIFY, LOWORD(lParam)); } - switch(_currentState) { - case STATE_MACRO: - case STATE_USER: { - _rightClickMenu.enableItem(IDM_BABYGRID_DELETE, true); - break; } - case STATE_MENU: - case STATE_PLUGIN: - case STATE_SCINTILLA: { + + case BGN_CELLRCLICKED: //a cell was clicked in the properties grid + { + POINT p; + ::GetCursorPos(&p); + if (!_rightClickMenu.isCreated()) + { + vector 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); - break; } + } + 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; } - - _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 & vShortcuts = nppParam->getUserShortcuts(); + findKeyConflicts(&conflictInfo, vShortcuts[currentIndex].getKeyCombo(), currentIndex); + break; + } + case STATE_MACRO: + { + vector & vShortcuts = nppParam->getMacroList(); + findKeyConflicts(&conflictInfo, vShortcuts[currentIndex].getKeyCombo(), currentIndex); + break; + } + case STATE_USER: + { + vector & vShortcuts = nppParam->getUserCommandList(); + findKeyConflicts(&conflictInfo, vShortcuts[currentIndex].getKeyCombo(), currentIndex); + break; + } + case STATE_PLUGIN: + { + vector & vShortcuts = nppParam->getPluginCommandList(); + findKeyConflicts(&conflictInfo, vShortcuts[currentIndex].getKeyCombo(), currentIndex); + break; + } + case STATE_SCINTILLA: + { + vector & 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, (LPARAM)_defaultInfo.c_str()); + else + ::SendDlgItemMessage(_hSelf, IDC_BABYGRID_INFO, WM_SETTEXT, 0, (LPARAM)conflictInfo.c_str()); + + return TRUE; + } + } //switch (HIWORD(wParam)) } - } + } //switch (LOWORD(wParam)) } default: return FALSE; - } + } //switch (message) return FALSE; } + +bool ShortcutMapper::findKeyConflicts(__inout_opt generic_string * const keyConflictLocation, + const KeyCombo & itemKeyComboToTest, const size_t & itemIndexToTest) const +{ + if (itemKeyComboToTest._key == NULL) //no key assignment + return false; + + bool retIsConflict = false; //returns true when a conflict is found + NppParameters * nppParam = NppParameters::getInstance(); + + for (size_t gridState = STATE_MENU; gridState <= STATE_SCINTILLA; ++gridState) + { + switch (gridState) + { + case STATE_MENU: + { + vector & vShortcuts = nppParam->getUserShortcuts(); + size_t nrItems = vShortcuts.size(); + for (size_t itemIndex = 0; itemIndex < nrItems; ++itemIndex) + { + if (not vShortcuts[itemIndex].isEnabled()) //no key assignment + continue; + + if ((itemIndex == itemIndexToTest) && (gridState == static_cast(_currentState))) //don't catch oneself + continue; + + if (isConflict(vShortcuts[itemIndex].getKeyCombo(), itemKeyComboToTest)) + { + retIsConflict = true; + if (keyConflictLocation == nullptr) + return retIsConflict; + else + { + if (not keyConflictLocation->empty()) + *keyConflictLocation += TEXT("\r\n"); + *keyConflictLocation += tabNames[gridState]; + *keyConflictLocation += TEXT(" | "); + *keyConflictLocation += numToStr(itemIndex + 1); + *keyConflictLocation += TEXT(" "); + *keyConflictLocation += vShortcuts[itemIndex].getName(); + *keyConflictLocation += TEXT(" ( "); + *keyConflictLocation += vShortcuts[itemIndex].toString(); + *keyConflictLocation += TEXT(" )"); + } + } + } + break; + } //case STATE_MENU + case STATE_MACRO: + { + vector & vShortcuts = nppParam->getMacroList(); + size_t nrItems = vShortcuts.size(); + for (size_t itemIndex = 0; itemIndex < nrItems; ++itemIndex) + { + if (not vShortcuts[itemIndex].isEnabled()) //no key assignment + continue; + + if ((itemIndex == itemIndexToTest) && (gridState == static_cast(_currentState))) //don't catch oneself + continue; + + if (isConflict(vShortcuts[itemIndex].getKeyCombo(), itemKeyComboToTest)) + { + retIsConflict = true; + if (keyConflictLocation == nullptr) + return retIsConflict; + else + { + if (not keyConflictLocation->empty()) + *keyConflictLocation += TEXT("\r\n"); + *keyConflictLocation += tabNames[gridState]; + *keyConflictLocation += TEXT(" | "); + *keyConflictLocation += numToStr(itemIndex + 1); + *keyConflictLocation += TEXT(" "); + *keyConflictLocation += vShortcuts[itemIndex].getName(); + *keyConflictLocation += TEXT(" ( "); + *keyConflictLocation += vShortcuts[itemIndex].toString(); + *keyConflictLocation += TEXT(" )"); + } + } + } + break; + } //case STATE_MACRO + case STATE_USER: + { + vector & vShortcuts = nppParam->getUserCommandList(); + size_t nrItems = vShortcuts.size(); + for (size_t itemIndex = 0; itemIndex < nrItems; ++itemIndex) + { + if (not vShortcuts[itemIndex].isEnabled()) //no key assignment + continue; + + if ((itemIndex == itemIndexToTest) && (gridState == static_cast(_currentState))) //don't catch oneself + continue; + + if (isConflict(vShortcuts[itemIndex].getKeyCombo(), itemKeyComboToTest)) + { + retIsConflict = true; + if (keyConflictLocation == nullptr) + return retIsConflict; + else + { + if (not keyConflictLocation->empty()) + *keyConflictLocation += TEXT("\r\n"); + *keyConflictLocation += tabNames[gridState]; + *keyConflictLocation += TEXT(" | "); + *keyConflictLocation += numToStr(itemIndex + 1); + *keyConflictLocation += TEXT(" "); + *keyConflictLocation += vShortcuts[itemIndex].getName(); + *keyConflictLocation += TEXT(" ( "); + *keyConflictLocation += vShortcuts[itemIndex].toString(); + *keyConflictLocation += TEXT(" )"); + } + } + } + break; + } //case STATE_USER + case STATE_PLUGIN: + { + vector & vShortcuts = nppParam->getPluginCommandList(); + size_t nrItems = vShortcuts.size(); + for (size_t itemIndex = 0; itemIndex < nrItems; ++itemIndex) + { + if (not vShortcuts[itemIndex].isEnabled()) //no key assignment + continue; + + if ((itemIndex == itemIndexToTest) && (gridState == static_cast(_currentState))) //don't catch oneself + continue; + + if (isConflict(vShortcuts[itemIndex].getKeyCombo(), itemKeyComboToTest)) + { + retIsConflict = true; + if (keyConflictLocation == nullptr) + return retIsConflict; + else + { + if (not keyConflictLocation->empty()) + *keyConflictLocation += TEXT("\r\n"); + *keyConflictLocation += tabNames[gridState]; + *keyConflictLocation += TEXT(" | "); + *keyConflictLocation += numToStr(itemIndex + 1); + *keyConflictLocation += TEXT(" "); + *keyConflictLocation += vShortcuts[itemIndex].getName(); + *keyConflictLocation += TEXT(" ( "); + *keyConflictLocation += vShortcuts[itemIndex].toString(); + *keyConflictLocation += TEXT(" )"); + } + } + } + break; + } //case STATE_PLUGIN + case STATE_SCINTILLA: + { + vector & vShortcuts = nppParam->getScintillaKeyList(); + size_t nrItems = vShortcuts.size(); + for (size_t itemIndex = 0; itemIndex < nrItems; ++itemIndex) + { + if (not vShortcuts[itemIndex].isEnabled()) //no key assignment + continue; + + if ((itemIndex == itemIndexToTest) && (gridState == static_cast(_currentState))) //don't catch oneself + continue; + + size_t sciCombos = vShortcuts[itemIndex].getSize(); + for (size_t sciIndex = 0; sciIndex < sciCombos; ++sciIndex) + { + if (isConflict(vShortcuts[itemIndex].getKeyComboByIndex(sciIndex), itemKeyComboToTest)) + { + retIsConflict = true; + if (keyConflictLocation == nullptr) + return retIsConflict; + else + { + if (not keyConflictLocation->empty()) + *keyConflictLocation += TEXT("\r\n"); + *keyConflictLocation += tabNames[gridState]; + *keyConflictLocation += TEXT(" | "); + *keyConflictLocation += numToStr(itemIndex + 1); + if (sciIndex > 0) + *keyConflictLocation += TEXT("* "); + else + *keyConflictLocation += TEXT(" "); + *keyConflictLocation += vShortcuts[itemIndex].getName(); + *keyConflictLocation += TEXT(" ( "); + *keyConflictLocation += vShortcuts[itemIndex].toString(sciIndex); + *keyConflictLocation += TEXT(" )"); + } + } + } + } + break; + } //case STATE_SCINTILLA + } //switch (gridState) + } //for (...) + return retIsConflict; +} diff --git a/PowerEditor/src/WinControls/Grid/ShortcutMapper.h b/PowerEditor/src/WinControls/Grid/ShortcutMapper.h index 14201074..d196c2da 100644 --- a/PowerEditor/src/WinControls/Grid/ShortcutMapper.h +++ b/PowerEditor/src/WinControls/Grid/ShortcutMapper.h @@ -66,6 +66,9 @@ public: void getClientRect(RECT & rc) const; void translateTab(int index, const TCHAR * newname); + bool findKeyConflicts(__inout_opt generic_string * const keyConflictLocation, + const KeyCombo & itemKeyCombo, const size_t & itemIndex) const; + protected : INT_PTR CALLBACK run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam); @@ -79,8 +82,32 @@ private: TCHAR tabNames[5][maxTabName]; + //save/restore the last view + std::vector _lastHomeRow; + std::vector _lastCursorRow; + + const generic_string _defaultInfo = TEXT("No schortcut conflicts for this item."); + const generic_string _assignInfo = TEXT("No conflicts . . ."); + + std::vector _hGridFonts; + + enum GridFonts : uint_fast8_t + { + GFONT_HEADER, + GFONT_ROWS, + MAX_GRID_FONTS + }; + void initTabs(); void initBabyGrid(); void fillOutBabyGrid(); + + bool isConflict(const KeyCombo & lhs, const KeyCombo & rhs) const + { + return ( (lhs._isCtrl == rhs._isCtrl ) && + (lhs._isAlt == rhs._isAlt ) && + (lhs._isShift == rhs._isShift) && + (lhs._key == rhs._key ) ); + } }; diff --git a/PowerEditor/src/WinControls/Grid/ShortcutMapper.rc b/PowerEditor/src/WinControls/Grid/ShortcutMapper.rc index f30b897e..0e7e540e 100644 --- a/PowerEditor/src/WinControls/Grid/ShortcutMapper.rc +++ b/PowerEditor/src/WinControls/Grid/ShortcutMapper.rc @@ -40,8 +40,9 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | CAPTION "Shortcut mapper" FONT 8, TEXT("MS Shell Dlg"), 400, 0, 0x1 BEGIN - CONTROL "",IDC_BABYGRID_TABBAR,"SysTabControl32",TCS_BUTTONS,6,6,372,12 + CONTROL "",IDC_BABYGRID_TABBAR,"SysTabControl32",WS_TABSTOP,4,6,384,12 DEFPUSHBUTTON "Modify",IDM_BABYGRID_MODIFY,118,319,47,14 DEFPUSHBUTTON "Delete",IDM_BABYGRID_DELETE,172,319,47,14 DEFPUSHBUTTON "Close",IDOK,226,319,47,14 + EDITTEXT IDC_BABYGRID_INFO,4,279,383,29,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | NOT WS_TABSTOP END diff --git a/PowerEditor/src/WinControls/Grid/ShortcutMapper_rc.h b/PowerEditor/src/WinControls/Grid/ShortcutMapper_rc.h index 84b1ed20..8b8c8862 100644 --- a/PowerEditor/src/WinControls/Grid/ShortcutMapper_rc.h +++ b/PowerEditor/src/WinControls/Grid/ShortcutMapper_rc.h @@ -34,5 +34,6 @@ #define IDM_BABYGRID_MODIFY (IDD_SHORTCUTMAPPER_DLG + 2) #define IDM_BABYGRID_DELETE (IDD_SHORTCUTMAPPER_DLG + 3) #define IDC_BABYGRID_TABBAR (IDD_SHORTCUTMAPPER_DLG + 4) +#define IDC_BABYGRID_INFO (IDD_SHORTCUTMAPPER_DLG + 5) #endif// SHORTCUTMAPPER_RC_H diff --git a/PowerEditor/src/WinControls/StaticDialog/RunDlg/RunDlg.cpp b/PowerEditor/src/WinControls/StaticDialog/RunDlg/RunDlg.cpp index 567c2a65..f8d9144c 100644 --- a/PowerEditor/src/WinControls/StaticDialog/RunDlg/RunDlg.cpp +++ b/PowerEditor/src/WinControls/StaticDialog/RunDlg/RunDlg.cpp @@ -196,10 +196,15 @@ HINSTANCE Command::run(HWND hWnd) return res; } -INT_PTR CALLBACK RunDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM) +INT_PTR CALLBACK RunDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { + case NPPM_INTERNAL_FINDKEYCONFLICTS: + { + return ::SendMessage(_hParent, message, wParam, lParam); + } + case WM_COMMAND : { switch (wParam) diff --git a/PowerEditor/src/WinControls/shortcut/shortcut.cpp b/PowerEditor/src/WinControls/shortcut/shortcut.cpp index dcf69963..422c6fec 100644 --- a/PowerEditor/src/WinControls/shortcut/shortcut.cpp +++ b/PowerEditor/src/WinControls/shortcut/shortcut.cpp @@ -362,6 +362,22 @@ void getNameStrFromCmd(DWORD cmd, generic_string & str) return; } +void Shortcut::updateConflictState(const bool endSession) const +{ + if (endSession) + { + // Clean up message for detached dialogs: save Macros/RunCommands + ::SendMessage(_hParent, NPPM_INTERNAL_FINDKEYCONFLICTS, 0, 0); + return; + } + + // Check for conflicts + bool isConflict = false; + ::SendMessage(_hParent, NPPM_INTERNAL_FINDKEYCONFLICTS, + reinterpret_cast(&_keyCombo), reinterpret_cast(&isConflict)); + ::ShowWindow(::GetDlgItem(_hSelf, IDC_CONFLICT_STATIC), isConflict ? SW_SHOW : SW_HIDE); +} + INT_PTR CALLBACK Shortcut::run_dlgProc(UINT Message, WPARAM wParam, LPARAM) { switch (Message) @@ -389,7 +405,7 @@ INT_PTR CALLBACK Shortcut::run_dlgProc(UINT Message, WPARAM wParam, LPARAM) if (iFound != -1) ::SendDlgItemMessage(_hSelf, IDC_KEY_COMBO, CB_SETCURSEL, iFound, 0); ::ShowWindow(::GetDlgItem(_hSelf, IDC_WARNING_STATIC), isEnabled()?SW_HIDE:SW_SHOW); - + updateConflictState(); goToCenter(); return TRUE; } @@ -402,15 +418,18 @@ INT_PTR CALLBACK Shortcut::run_dlgProc(UINT Message, WPARAM wParam, LPARAM) case IDC_CTRL_CHECK : _keyCombo._isCtrl = BST_CHECKED == ::SendDlgItemMessage(_hSelf, static_cast(wParam), BM_GETCHECK, 0, 0); ::EnableWindow(::GetDlgItem(_hSelf, IDOK), isValid() && (textlen > 0 || !_canModifyName)); + updateConflictState(); return TRUE; case IDC_ALT_CHECK : _keyCombo._isAlt = BST_CHECKED == ::SendDlgItemMessage(_hSelf, static_cast(wParam), BM_GETCHECK, 0, 0); ::EnableWindow(::GetDlgItem(_hSelf, IDOK), isValid() && (textlen > 0 || !_canModifyName)); + updateConflictState(); return TRUE; case IDC_SHIFT_CHECK : _keyCombo._isShift = BST_CHECKED == ::SendDlgItemMessage(_hSelf, static_cast(wParam), BM_GETCHECK, 0, 0); + updateConflictState(); return TRUE; case IDOK : @@ -423,10 +442,12 @@ INT_PTR CALLBACK Shortcut::run_dlgProc(UINT Message, WPARAM wParam, LPARAM) setName(editName); } ::EndDialog(_hSelf, 0); + updateConflictState(true); return TRUE; case IDCANCEL : ::EndDialog(_hSelf, -1); + updateConflictState(true); return TRUE; default: @@ -446,6 +467,7 @@ INT_PTR CALLBACK Shortcut::run_dlgProc(UINT Message, WPARAM wParam, LPARAM) _keyCombo._key = namedKeyArray[i].id; ::EnableWindow(::GetDlgItem(_hSelf, IDOK), isValid() && (textlen > 0 || !_canModifyName)); ::ShowWindow(::GetDlgItem(_hSelf, IDC_WARNING_STATIC), isEnabled()?SW_HIDE:SW_SHOW); + updateConflictState(); return TRUE; } } @@ -754,11 +776,23 @@ void ScintillaKeyMap::validateDialog() { bool valid = isValid(); //current combo valid? bool isDisabling = _keyCombo._key == 0; //true if this keycombo were to disable the shortcut bool isDisabled = !isEnabled(); //true if this shortcut already is + bool isDuplicate = false; //true if already in the list - ::EnableWindow(::GetDlgItem(_hSelf, IDC_BUTTON_ADD), valid && !isDisabling); - ::EnableWindow(::GetDlgItem(_hSelf, IDC_BUTTON_APPLY), valid && (!isDisabling || _size == 1)); + for (size_t i = 0; i < _size; ++i) + { + if (_keyCombo._key == _keyCombos[i]._key && _keyCombo._isCtrl == _keyCombos[i]._isCtrl && + _keyCombo._isAlt == _keyCombos[i]._isAlt && _keyCombo._isShift == _keyCombos[i]._isShift) + { + isDuplicate = true; + break; + } + } + + ::EnableWindow(::GetDlgItem(_hSelf, IDC_BUTTON_ADD), valid && !isDisabling && !isDuplicate); + ::EnableWindow(::GetDlgItem(_hSelf, IDC_BUTTON_APPLY), valid && (!isDisabling || _size == 1) && !isDuplicate); ::EnableWindow(::GetDlgItem(_hSelf, IDC_BUTTON_RMVE), (_size > 1)?TRUE:FALSE); ::ShowWindow(::GetDlgItem(_hSelf, IDC_WARNING_STATIC), isDisabled?SW_SHOW:SW_HIDE); + updateConflictState(); } void ScintillaKeyMap::showCurrentSettings() { @@ -829,6 +863,7 @@ INT_PTR CALLBACK ScintillaKeyMap::run_dlgProc(UINT Message, WPARAM wParam, LPARA case IDC_SHIFT_CHECK : _keyCombo._isShift = BST_CHECKED == ::SendDlgItemMessage(_hSelf, static_cast(wParam), BM_GETCHECK, 0, 0); //applyToCurrentIndex(); + validateDialog(); return TRUE; case IDOK : @@ -896,6 +931,7 @@ INT_PTR CALLBACK ScintillaKeyMap::run_dlgProc(UINT Message, WPARAM wParam, LPARA case IDC_LIST_KEYS: { showCurrentSettings(); + validateDialog(); return TRUE; } } diff --git a/PowerEditor/src/WinControls/shortcut/shortcut.h b/PowerEditor/src/WinControls/shortcut/shortcut.h index 2a5dddea..e4f8d9c0 100644 --- a/PowerEditor/src/WinControls/shortcut/shortcut.h +++ b/PowerEditor/src/WinControls/shortcut/shortcut.h @@ -180,6 +180,7 @@ protected : bool _canModifyName; TCHAR _name[nameLenMax]; //normal name is plain text (for display purposes) TCHAR _menuName[nameLenMax]; //menu name has ampersands for quick keys + void updateConflictState(const bool endSession = false) const; }; class CommandShortcut : public Shortcut { diff --git a/PowerEditor/src/WinControls/shortcut/shortcut.rc b/PowerEditor/src/WinControls/shortcut/shortcut.rc index 99560df6..8549e889 100644 --- a/PowerEditor/src/WinControls/shortcut/shortcut.rc +++ b/PowerEditor/src/WinControls/shortcut/shortcut.rc @@ -52,10 +52,10 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,103,73,50,14 LTEXT "+",IDC_STATIC,45,42,8,8 LTEXT "+",IDC_STATIC,96,42,8,8 - EDITTEXT IDC_NAME_EDIT,56,9,93,14,ES_AUTOHSCROLL + EDITTEXT IDC_NAME_EDIT,56,9,118,14,ES_AUTOHSCROLL LTEXT "Name :",IDC_NAME_STATIC,15,12,34,8,0,WS_EX_RIGHT - LTEXT "This will disable the accelerator!",IDC_WARNING_STATIC, - 6,90,170,8 + LTEXT "This will disable the accelerator!",IDC_WARNING_STATIC,6,91,170,8 + LTEXT "CONFLICT FOUND!",IDC_CONFLICT_STATIC,6,91,170,8 END IDD_SHORTCUTSCINT_DLG DIALOGEX 0, 0, 286, 114 @@ -76,10 +76,10 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,210,78,48,14 LTEXT "+",IDC_STATIC,147,39,8,8 LTEXT "+",IDC_STATIC,198,39,8,8 - EDITTEXT IDC_NAME_EDIT,158,6,93,14,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_NAME_EDIT,158,6,118,14,ES_AUTOHSCROLL | ES_READONLY LTEXT "Name :",IDC_NAME_STATIC,117,9,34,8,0,WS_EX_RIGHT - LTEXT "This will remove the accelerator!",IDC_WARNING_STATIC, - 120,98,138,8 + LTEXT "This will remove the accelerator!",IDC_WARNING_STATIC,114,99,162,8 + LTEXT "CONFLICT FOUND!",IDC_CONFLICT_STATIC,114,99,162,8 LISTBOX IDC_LIST_KEYS,6,6,90,72,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Add",IDC_BUTTON_ADD,6,84,42,14 diff --git a/PowerEditor/src/WinControls/shortcut/shortcutRc.h b/PowerEditor/src/WinControls/shortcut/shortcutRc.h index 0f0101dc..a1dafc52 100644 --- a/PowerEditor/src/WinControls/shortcut/shortcutRc.h +++ b/PowerEditor/src/WinControls/shortcut/shortcutRc.h @@ -42,4 +42,5 @@ #define IDC_BUTTON_RMVE (IDD_SHORTCUT_DLG + 9) #define IDC_BUTTON_APPLY (IDD_SHORTCUT_DLG + 10) #define IDC_LIST_KEYS (IDD_SHORTCUT_DLG + 11) +#define IDC_CONFLICT_STATIC (IDD_SHORTCUT_DLG + 12) #endif //IDD_SHORTCUT_DLG diff --git a/PowerEditor/src/resource.h b/PowerEditor/src/resource.h index bfc4a926..ac47769e 100644 --- a/PowerEditor/src/resource.h +++ b/PowerEditor/src/resource.h @@ -407,6 +407,7 @@ #define NPPM_INTERNAL_FINDINFINDERDLG (NOTEPADPLUS_USER_INTERNAL + 40) #define NPPM_INTERNAL_REMOVEFINDER (NOTEPADPLUS_USER_INTERNAL + 41) #define NPPM_INTERNAL_RELOADSCROLLTOEND (NOTEPADPLUS_USER_INTERNAL + 42) // Used by Monitoring feature + #define NPPM_INTERNAL_FINDKEYCONFLICTS (NOTEPADPLUS_USER_INTERNAL + 43) //wParam: 0 //lParam: document new index