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.
This commit is contained in:
A-R-C-A 2016-07-11 23:24:05 +00:00 committed by Don HO
parent 80ddd05197
commit 1abac15799
16 changed files with 885 additions and 101 deletions

View File

@ -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;

View File

@ -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<bool*>(lParam) = _pShortcutMapper->findKeyConflicts(nullptr, *reinterpret_cast<KeyCombo*>(wParam), (size_t)-1);
return TRUE;
}
case NPPM_INTERNAL_SETCARETWIDTH:
{
NppGUI & nppGUI = (NppGUI &)pNppParam->getNppGUI();

View File

@ -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<int32_t>(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<int32_t>(SendMessage(hWnd, BGM_GETPROTECTION, (WPARAM)&BGcell, 0));
//iProtection = static_cast<int32_t>(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<int32_t>(SendMessage(hWnd, BGM_GETTYPE, (WPARAM)&BGcell, 0));
//iDataType = static_cast<int32_t>(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<int32_t>(wParam);
BGHS[SelfIndex].homecol = 1;
BGHS[SelfIndex].cursorrow = static_cast<int32_t>(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<k;j++)
@ -1853,6 +1919,10 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
}
break;
case BGM_GETHOMEROW:
ReturnValue = BGHS[SelfIndex].homerow;
break;
case BGM_GETROW:
ReturnValue = BGHS[SelfIndex].cursorrow;
break;
@ -1972,6 +2042,32 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
}
break;
case BGM_SETHILIGHTCOLOR_NOFOCUS:
BGHS[SelfIndex].highlightcolorNoFocus = (COLORREF)wParam;
{
RECT rect;
GetClientRect(hWnd,&rect);
InvalidateRect(hWnd,&rect,FALSE);
}
break;
case BGM_SETHILIGHTCOLOR_PROTECT:
BGHS[SelfIndex].highlightcolorProtect = (COLORREF)wParam;
{
RECT rect;
GetClientRect(hWnd,&rect);
InvalidateRect(hWnd,&rect,FALSE);
}
break;
case BGM_SETHILIGHTCOLOR_PROTECT_NOFOCUS:
BGHS[SelfIndex].highlightcolorProtectNoFocus = (COLORREF)wParam;
{
RECT rect;
GetClientRect(hWnd,&rect);
InvalidateRect(hWnd,&rect,FALSE);
}
break;
case BGM_SETPROTECTCOLOR:
BGHS[SelfIndex].protectcolor = (COLORREF)wParam;
@ -2193,7 +2289,7 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
if(NCC){NotifyColChanged(hWnd,SelfIndex);}
DrawCursor(hWnd,SelfIndex);
SetCurrentCellStatus(hWnd,SelfIndex);
//SetCurrentCellStatus(hWnd,SelfIndex); //redundant
SetHomeRow(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
SetHomeCol(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
RefreshGrid(hWnd);
@ -2228,7 +2324,7 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
}
DrawCursor(hWnd,SelfIndex);
SetCurrentCellStatus(hWnd,SelfIndex);
//SetCurrentCellStatus(hWnd,SelfIndex); //redundant
SetHomeRow(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
RefreshGrid(hWnd);
BGHS[SelfIndex].EDITING = FALSE;
@ -2362,7 +2458,7 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
}
NotifyRowChanged(hWnd,SelfIndex);
DrawCursor(hWnd,SelfIndex);
SetCurrentCellStatus(hWnd,SelfIndex);
//SetCurrentCellStatus(hWnd,SelfIndex); //redundant
SetHomeRow(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
SetHomeCol(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
RefreshGrid(hWnd);
@ -2391,7 +2487,7 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
}
NotifyRowChanged(hWnd,SelfIndex);
DrawCursor(hWnd,SelfIndex);
SetCurrentCellStatus(hWnd,SelfIndex);
//SetCurrentCellStatus(hWnd,SelfIndex); //redundant
SetHomeRow(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
SetHomeCol(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
RefreshGrid(hWnd);
@ -2417,7 +2513,7 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
NotifyRowChanged(hWnd,SelfIndex);
}
DrawCursor(hWnd,SelfIndex);
SetCurrentCellStatus(hWnd,SelfIndex);
//SetCurrentCellStatus(hWnd,SelfIndex); //redundant
SetHomeRow(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
SetHomeCol(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
RefreshGrid(hWnd);
@ -2444,7 +2540,7 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
NotifyRowChanged(hWnd,SelfIndex);
}
DrawCursor(hWnd,SelfIndex);
SetCurrentCellStatus(hWnd,SelfIndex);
//SetCurrentCellStatus(hWnd,SelfIndex); //redundant
SetHomeRow(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
SetHomeCol(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
RefreshGrid(hWnd);
@ -2471,7 +2567,7 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
NotifyColChanged(hWnd,SelfIndex);
}
DrawCursor(hWnd,SelfIndex);
SetCurrentCellStatus(hWnd,SelfIndex);
//SetCurrentCellStatus(hWnd,SelfIndex); //redundant
SetHomeRow(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
SetHomeCol(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
break;
@ -2492,7 +2588,7 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
NotifyColChanged(hWnd,SelfIndex);
}
DrawCursor(hWnd,SelfIndex);
SetCurrentCellStatus(hWnd,SelfIndex);
//SetCurrentCellStatus(hWnd,SelfIndex); //redundant
SetHomeRow(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
SetHomeCol(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
RefreshGrid(hWnd);
@ -2517,7 +2613,7 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
NotifyRowChanged(hWnd,SelfIndex);
}
DrawCursor(hWnd,SelfIndex);
SetCurrentCellStatus(hWnd,SelfIndex);
//SetCurrentCellStatus(hWnd,SelfIndex); //redundant
SetHomeRow(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
RefreshGrid(hWnd);
break;
@ -2543,7 +2639,7 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
NotifyRowChanged(hWnd,SelfIndex);
}
DrawCursor(hWnd,SelfIndex);
SetCurrentCellStatus(hWnd,SelfIndex);
//SetCurrentCellStatus(hWnd,SelfIndex); //redundant
SetHomeRow(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
RefreshGrid(hWnd);
break;
@ -2617,7 +2713,7 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
NotifyRowChanged(hWnd,SelfIndex);
}
DrawCursor(hWnd,SelfIndex);
SetCurrentCellStatus(hWnd,SelfIndex);
//SetCurrentCellStatus(hWnd,SelfIndex); //redundant
SetHomeRow(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
RefreshGrid(hWnd);
BGHS[SelfIndex].EDITING = FALSE;
@ -2837,7 +2933,7 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
DrawCursor(hWnd,SelfIndex);
BGHS[SelfIndex].GRIDHASFOCUS = TRUE;
DrawCursor(hWnd,SelfIndex);
SetCurrentCellStatus(hWnd,SelfIndex);
//SetCurrentCellStatus(hWnd,SelfIndex); //redundant
SetHomeRow(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
SetHomeCol(hWnd,SelfIndex,BGHS[SelfIndex].cursorrow,BGHS[SelfIndex].cursorcol);
@ -2878,7 +2974,64 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
}
RefreshGrid(hWnd);
break;
case WM_SIZE:
case WM_SIZE:
{
//This function needs a static placement position inside a parent window (default in Npp).
//For a dynamic position (e.g. sizing of the parenet window) an adjustment to this function is needed!
if (not BGHS[SelfIndex].SHOWINTEGRALROWS)
break;
ShowHscroll(hWnd, SelfIndex);
ShowVscroll(hWnd, SelfIndex);
if (BGHS[SelfIndex].VSCROLL)
{
static int masterHeight = 0; //initial height
WINDOWPLACEMENT wp;
wp.length = sizeof(wp);
::GetWindowPlacement(hWnd, &wp);
if (masterHeight < 1)
{
masterHeight = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
if (masterHeight < 1)
break;
}
int outerHeight = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
int innerHeight = outerHeight;
innerHeight -= BGHS[SelfIndex].titleheight;
innerHeight -= BGHS[SelfIndex].headerrowheight;
if (::GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_CLIENTEDGE)
innerHeight -= ::GetSystemMetrics(SM_CYEDGE) * 2;
if (BGHS[SelfIndex].HSCROLL)
innerHeight -= ::GetSystemMetrics(SM_CYHSCROLL);
if (innerHeight <= BGHS[SelfIndex].rowheight * 4)
break;
else
{
int remainder = innerHeight % BGHS[SelfIndex].rowheight;
if ((outerHeight + BGHS[SelfIndex].rowheight - remainder) <= masterHeight)
outerHeight += BGHS[SelfIndex].rowheight - remainder;
else
outerHeight -= remainder;
wp.rcNormalPosition.bottom = wp.rcNormalPosition.top + outerHeight;
::SetWindowPlacement(hWnd, &wp);
}
}
}
break;
/* case WM_SIZE: //obsolete
{
static int SI,cheight;
static int savewidth,saveheight;
@ -2960,7 +3113,7 @@ LRESULT CALLBACK GridProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
}
}
break;
break; */
case WM_CREATE:
lpcs = &cs;
lpcs = (LPCREATESTRUCT)lParam;

View File

@ -92,6 +92,12 @@
#define BGM_SETALLOWCOLRESIZE BABYGRID_USER + 42
#define BGM_SETTITLEFONT BABYGRID_USER + 43
#define BGM_SETHEADINGFONT BABYGRID_USER + 44
#define BGM_GETHOMEROW BABYGRID_USER + 45
#define BGM_SETLASTVIEW BABYGRID_USER + 46
#define BGM_SETINITIALCONTENT BABYGRID_USER + 47
#define BGM_SETHILIGHTCOLOR_NOFOCUS BABYGRID_USER + 48
#define BGM_SETHILIGHTCOLOR_PROTECT BABYGRID_USER + 49
#define BGM_SETHILIGHTCOLOR_PROTECT_NOFOCUS BABYGRID_USER + 50
struct _BGCELL {
int row;

View File

@ -41,7 +41,7 @@ void BabyGridWrapper::init(HINSTANCE hInst, HWND parent, int id)
_hSelf = ::CreateWindowEx(WS_EX_CLIENTEDGE,
babyGridClassName,\
TEXT(""),\
WS_CHILD | WS_VISIBLE,\
WS_CHILD | WS_VISIBLE | WS_TABSTOP,\
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,\
_hParent,\
(HMENU)id,\

View File

@ -90,6 +90,67 @@ public :
::SendMessage(_hSelf, BGM_CLEARGRID, 0, 0);
};
int getNumberRows() const {
return (int)::SendMessage(_hSelf, BGM_GETROWS, 0, 0);
};
int getHomeRow() const {
return (int)::SendMessage(_hSelf, BGM_GETHOMEROW, 0, 0);
};
void setLastView(const size_t homeRow, const size_t cursorRow) const {
::SendMessage(_hSelf, BGM_SETLASTVIEW, homeRow, cursorRow);
};
void updateView() const {
::SendMessage(_hSelf, WM_PAINT, 0, 0);
};
void setHighlightColorNoFocus(const COLORREF color) const {
::SendMessage(_hSelf, BGM_SETHILIGHTCOLOR_NOFOCUS, color, 0);
};
void setProtectColor(const COLORREF color) const {
::SendMessage(_hSelf, BGM_SETPROTECTCOLOR, color, 0);
};
void setHighlightColorProtect(const COLORREF color) const {
::SendMessage(_hSelf, BGM_SETHILIGHTCOLOR_PROTECT, color, 0);
};
void setHighlightColorProtectNoFocus(const COLORREF color) const {
::SendMessage(_hSelf, BGM_SETHILIGHTCOLOR_PROTECT_NOFOCUS, color, 0);
};
bool setMarker(const bool isMarker) const {
::SendMessage(_hSelf, BGM_SETPROTECT, isMarker, 0);
return isMarker;
};
void setAutoRow(const bool isAutoRow) const {
::SendMessage(_hSelf, BGM_AUTOROW, isAutoRow, 0);
};
void setInitialContent(const bool isInitialContent) const {
::SendMessage(_hSelf, BGM_SETINITIALCONTENT, isInitialContent, 0);
};
void setHeaderFont(const HFONT & hFont) const {
::SendMessage(_hSelf, BGM_SETHEADINGFONT, (WPARAM)hFont, 0);
};
void setRowFont(const HFONT & hFont) const {
::SendMessage(_hSelf, WM_SETFONT, (WPARAM)hFont, 0);
};
void setHeaderHeight(const size_t headerHeight) const {
::SendMessage(_hSelf, BGM_SETHEADERROWHEIGHT, headerHeight, 0);
};
void setRowHeight(const size_t rowHeight) const {
::SendMessage(_hSelf, BGM_SETROWHEIGHT, rowHeight, 0);
};
private :
static bool _isRegistered;
};

View File

@ -29,6 +29,12 @@
#include "ShortcutMapper.h"
#include "Notepad_plus.h"
#ifdef UNICODE
#define numToStr std::to_wstring
#else
#define numToStr std::to_string
#endif //UNICODE
using namespace std;
void ShortcutMapper::initTabs() {
@ -47,16 +53,31 @@ void ShortcutMapper::initTabs() {
::SendMessage(hTab, TCM_INSERTITEM, 4, (LPARAM)(&tie) );
TabCtrl_SetCurSel(_hTabCtrl, int(_currentState));
//force alignment to babygrid on higher dpi
if (NppParameters::getInstance()->_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<CommandShortcut> & 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<MacroShortcut> & 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<UserCommand> & 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<PluginCmdShortcut> & 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<ScintillaKeyMap> & 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<KeyCombo*>(wParam), _babygrid.getSelectedRow() - 1);
*reinterpret_cast<bool*>(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<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
@ -395,6 +574,17 @@ INT_PTR CALLBACK ShortcutMapper::run_dlgProc(UINT message, WPARAM wParam, LPARAM
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
@ -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<MenuItemUnit> 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<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);
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<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, (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<CommandShortcut> & 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<size_t>(_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<MacroShortcut> & 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<size_t>(_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<UserCommand> & 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<size_t>(_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<PluginCmdShortcut> & 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<size_t>(_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<ScintillaKeyMap> & 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<size_t>(_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;
}

View File

@ -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<size_t> _lastHomeRow;
std::vector<size_t> _lastCursorRow;
const generic_string _defaultInfo = TEXT("No schortcut conflicts for this item.");
const generic_string _assignInfo = TEXT("No conflicts . . .");
std::vector<HFONT> _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 ) );
}
};

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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<WPARAM>(&_keyCombo), reinterpret_cast<LPARAM>(&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<int32_t>(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<int32_t>(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<int32_t>(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<int32_t>(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;
}
}

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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