notepad-plus-plus-legacy/PowerEditor/src/WinControls/FunctionList/functionListPanel.cpp

919 lines
27 KiB
C++

// This file is part of Notepad++ project
// Copyright (C)2020 Don HO <don.h@free.fr>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// Note that the GPL places important restrictions on "derived works", yet
// it does not provide a detailed definition of that term. To avoid
// misunderstandings, we consider an application to constitute a
// "derivative work" for the purpose of this license if it does any of the
// following:
// 1. Integrates source code from Notepad++.
// 2. Integrates/includes/aggregates Notepad++ into a proprietary executable
// installer, such as those produced by InstallShield.
// 3. Links to a library or executes a program that does any of the above.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "json.hpp"
#include "functionListPanel.h"
#include "ScintillaEditView.h"
#include "localization.h"
#include <fstream>
using nlohmann::json;
using namespace std;
#define CX_BITMAP 16
#define CY_BITMAP 16
#define INDEX_ROOT 0
#define INDEX_NODE 1
#define INDEX_LEAF 2
FunctionListPanel::~FunctionListPanel()
{
for (const auto s : posStrs)
{
delete s;
}
}
void FunctionListPanel::addEntry(const TCHAR *nodeName, const TCHAR *displayText, size_t pos)
{
HTREEITEM itemParent = NULL;
TCHAR posStr[32];
generic_itoa(static_cast<int32_t>(pos), posStr, 10);
HTREEITEM root = _treeView.getRoot();
if (nodeName != NULL && *nodeName != '\0')
{
itemParent = _treeView.searchSubItemByName(nodeName, root);
if (!itemParent)
{
generic_string* invalidValueStr = new generic_string(TEXT("-1"));
posStrs.push_back(invalidValueStr);
LPARAM lParamInvalidPosStr = reinterpret_cast<LPARAM>(invalidValueStr);
itemParent = _treeView.addItem(nodeName, root, INDEX_NODE, lParamInvalidPosStr);
}
}
else
itemParent = root;
generic_string* posString = new generic_string(posStr);
posStrs.push_back(posString);
LPARAM lParamPosStr = reinterpret_cast<LPARAM>(posString);
_treeView.addItem(displayText, itemParent, INDEX_LEAF, lParamPosStr);
}
void FunctionListPanel::removeAllEntries()
{
_treeView.removeAllItems();
}
// bodyOpenSybe mbol & bodyCloseSymbol should be RE
size_t FunctionListPanel::getBodyClosePos(size_t begin, const TCHAR *bodyOpenSymbol, const TCHAR *bodyCloseSymbol)
{
size_t cntOpen = 1;
int docLen = (*_ppEditView)->getCurrentDocLen();
if (begin >= (size_t)docLen)
return docLen;
generic_string exprToSearch = TEXT("(");
exprToSearch += bodyOpenSymbol;
exprToSearch += TEXT("|");
exprToSearch += bodyCloseSymbol;
exprToSearch += TEXT(")");
int flags = SCFIND_REGEXP | SCFIND_POSIX;
(*_ppEditView)->execute(SCI_SETSEARCHFLAGS, flags);
int targetStart = (*_ppEditView)->searchInTarget(exprToSearch.c_str(), exprToSearch.length(), begin, docLen);
int targetEnd = 0;
do
{
if (targetStart != -1 && targetStart != -2) // found open or close symbol
{
targetEnd = int((*_ppEditView)->execute(SCI_GETTARGETEND));
// Now we determinate the symbol (open or close)
int tmpStart = (*_ppEditView)->searchInTarget(bodyOpenSymbol, lstrlen(bodyOpenSymbol), targetStart, targetEnd);
if (tmpStart != -1 && tmpStart != -2) // open symbol found
{
++cntOpen;
}
else // if it's not open symbol, then it must be the close one
{
--cntOpen;
}
}
else // nothing found
{
cntOpen = 0; // get me out of here
targetEnd = static_cast<int32_t>(begin);
}
targetStart = (*_ppEditView)->searchInTarget(exprToSearch.c_str(), exprToSearch.length(), targetEnd, docLen);
} while (cntOpen);
return targetEnd;
}
generic_string FunctionListPanel::parseSubLevel(size_t begin, size_t end, std::vector< generic_string > dataToSearch, int & foundPos)
{
if (begin >= end)
{
foundPos = -1;
return TEXT("");
}
if (!dataToSearch.size())
return TEXT("");
int flags = SCFIND_REGEXP | SCFIND_POSIX;
(*_ppEditView)->execute(SCI_SETSEARCHFLAGS, flags);
const TCHAR *regExpr2search = dataToSearch[0].c_str();
int targetStart = (*_ppEditView)->searchInTarget(regExpr2search, lstrlen(regExpr2search), begin, end);
if (targetStart == -1 || targetStart == -2)
{
foundPos = -1;
return TEXT("");
}
int targetEnd = int((*_ppEditView)->execute(SCI_GETTARGETEND));
if (dataToSearch.size() >= 2)
{
dataToSearch.erase(dataToSearch.begin());
return parseSubLevel(targetStart, targetEnd, dataToSearch, foundPos);
}
else // only one processed element, so we conclude the result
{
TCHAR foundStr[1024];
(*_ppEditView)->getGenericText(foundStr, 1024, targetStart, targetEnd);
foundPos = targetStart;
return foundStr;
}
}
void FunctionListPanel::addInStateArray(TreeStateNode tree2Update, const TCHAR *searchText, bool isSorted)
{
bool found = false;
for (size_t i = 0, len = _treeParams.size(); i < len; ++i)
{
if (_treeParams[i]._treeState._extraData == tree2Update._extraData)
{
_treeParams[i]._searchParameters._text2Find = searchText;
_treeParams[i]._searchParameters._doSort = isSorted;
_treeParams[i]._treeState = tree2Update;
found = true;
}
}
if (!found)
{
TreeParams params;
params._treeState = tree2Update;
params._searchParameters._text2Find = searchText;
params._searchParameters._doSort = isSorted;
_treeParams.push_back(params);
}
}
TreeParams* FunctionListPanel::getFromStateArray(generic_string fullFilePath)
{
for (size_t i = 0, len = _treeParams.size(); i < len; ++i)
{
if (_treeParams[i]._treeState._extraData == fullFilePath)
return &_treeParams[i];
}
return NULL;
}
void FunctionListPanel::sortOrUnsort()
{
bool doSort = shouldSort();
if (doSort)
_pTreeView->sort(_pTreeView->getRoot(), true);
else
{
TCHAR text2search[MAX_PATH] ;
::SendMessage(_hSearchEdit, WM_GETTEXT, MAX_PATH, reinterpret_cast<LPARAM>(text2search));
if (text2search[0] == '\0') // main view
{
reload();
}
else // aux view
{
reload();
if (_treeView.getRoot() == NULL)
return;
_treeViewSearchResult.removeAllItems();
const TCHAR *fn = ((*_ppEditView)->getCurrentBuffer())->getFileName();
generic_string* invalidValueStr = new generic_string(TEXT("-1"));
posStrs.push_back(invalidValueStr);
LPARAM lParamInvalidPosStr = reinterpret_cast<LPARAM>(invalidValueStr);
_treeViewSearchResult.addItem(fn, NULL, INDEX_ROOT, lParamInvalidPosStr);
_treeView.searchLeafAndBuildTree(_treeViewSearchResult, text2search, INDEX_LEAF);
_treeViewSearchResult.display(true);
_treeViewSearchResult.expand(_treeViewSearchResult.getRoot());
_treeView.display(false);
_pTreeView = &_treeViewSearchResult;
}
}
}
bool FunctionListPanel::serialize(const generic_string & outputFilename)
{
Buffer* currentBuf = (*_ppEditView)->getCurrentBuffer();
const TCHAR* fileNameLabel = currentBuf->getFileName();
generic_string fname2write;
if (outputFilename.empty()) // if outputFilename is not given, get the current file path by adding the file extension
{
const TCHAR *fullFilePath = currentBuf->getFullPathName();
// Export function list from an existing file
bool exportFuncntionList = (NppParameters::getInstance()).doFunctionListExport();
if (exportFuncntionList && ::PathFileExists(fullFilePath))
{
fname2write = fullFilePath;
fname2write += TEXT(".result");
fname2write += TEXT(".json");
}
else
return false;
}
else
{
fname2write = outputFilename;
}
const char* rootLabel = "root";
const char* nodesLabel = "nodes";
const char* leavesLabel = "leaves";
const char* nameLabel = "name";
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
json j;
j[rootLabel] = wmc.wchar2char(fileNameLabel, CP_ACP);
for (const auto & info : _foundFuncInfos)
{
std::string leafName = wmc.wchar2char(info._data.c_str(), CP_ACP);
if (!info._data2.empty()) // node
{
bool isFound = false;
std::string nodeName = wmc.wchar2char(info._data2.c_str(), CP_ACP);
for (auto & i : j[nodesLabel])
{
if (nodeName == i[nameLabel])
{
i[leavesLabel].push_back(leafName.c_str());
isFound = true;
break;
}
}
if (!isFound)
{
json aNode = { { leavesLabel, json::array() },{ nameLabel, nodeName.c_str() } };
aNode[leavesLabel].push_back(leafName.c_str());
j[nodesLabel].push_back(aNode);
}
}
else // leaf
{
j[leavesLabel].push_back(leafName.c_str());
}
}
std::ofstream file(wmc.wchar2char(fname2write.c_str(), CP_ACP));
file << j;
return true;
}
void FunctionListPanel::reload()
{
// clean up
_findLine = -1;
_findEndLine = -1;
TreeStateNode currentTree;
bool isOK = _treeView.retrieveFoldingStateTo(currentTree, _treeView.getRoot());
if (isOK)
{
TCHAR text2Search[MAX_PATH];
::SendMessage(_hSearchEdit, WM_GETTEXT, MAX_PATH, reinterpret_cast<LPARAM>(text2Search));
bool isSorted = shouldSort();
addInStateArray(currentTree, text2Search, isSorted);
}
removeAllEntries();
::SendMessage(_hSearchEdit, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(TEXT("")));
setSort(false);
_foundFuncInfos.clear();
Buffer* currentBuf = (*_ppEditView)->getCurrentBuffer();
const TCHAR *fn = currentBuf->getFileName();
LangType langID = currentBuf->getLangType();
if (langID == L_JS)
langID = L_JAVASCRIPT;
const TCHAR *udln = NULL;
if (langID == L_USER)
{
udln = currentBuf->getUserDefineLangName();
}
TCHAR *ext = ::PathFindExtension(fn);
bool parsedOK = _funcParserMgr.parse(_foundFuncInfos, AssociationInfo(-1, langID, ext, udln));
if (parsedOK)
{
generic_string* invalidValueStr = new generic_string(TEXT("-1"));
posStrs.push_back(invalidValueStr);
LPARAM lParamInvalidPosStr = reinterpret_cast<LPARAM>(invalidValueStr);
_treeView.addItem(fn, NULL, INDEX_ROOT, lParamInvalidPosStr);
}
for (size_t i = 0, len = _foundFuncInfos.size(); i < len; ++i)
{
addEntry(_foundFuncInfos[i]._data2.c_str(), _foundFuncInfos[i]._data.c_str(), _foundFuncInfos[i]._pos);
}
HTREEITEM root = _treeView.getRoot();
if (root)
{
currentBuf = (*_ppEditView)->getCurrentBuffer();
const TCHAR *fullFilePath = currentBuf->getFullPathName();
generic_string* fullPathStr = new generic_string(fullFilePath);
posStrs.push_back(fullPathStr);
LPARAM lParamFullPathStr = reinterpret_cast<LPARAM>(fullPathStr);
_treeView.setItemParam(root, lParamFullPathStr);
TreeParams *previousParams = getFromStateArray(fullFilePath);
if (!previousParams)
{
::SendMessage(_hSearchEdit, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(TEXT("")));
setSort(false);
_treeView.expand(root);
}
else
{
::SendMessage(_hSearchEdit, WM_SETTEXT, 0, reinterpret_cast<LPARAM>((previousParams->_searchParameters)._text2Find.c_str()));
_treeView.restoreFoldingStateFrom(previousParams->_treeState, root);
bool isSort = (previousParams->_searchParameters)._doSort;
setSort(isSort);
if (isSort)
_pTreeView->sort(_pTreeView->getRoot(), true);
}
}
// invalidate the editor rect
::InvalidateRect(_hSearchEdit, NULL, TRUE);
}
void FunctionListPanel::markEntry()
{
LONG lineNr = static_cast<LONG>((*_ppEditView)->getCurrentLineNumber());
HTREEITEM root = _treeView.getRoot();
if (_findLine != -1 && _findEndLine != -1 && lineNr >= _findLine && lineNr < _findEndLine)
return;
_findLine = -1;
_findEndLine = -1;
findMarkEntry(root, lineNr);
if (_findLine != -1)
{
_treeView.selectItem(_findItem);
}
else
{
_treeView.selectItem(root);
}
}
void FunctionListPanel::findMarkEntry(HTREEITEM htItem, LONG line)
{
HTREEITEM cItem;
TVITEM tvItem;
for (; htItem != NULL; htItem = _treeView.getNextSibling(htItem))
{
cItem = _treeView.getChildFrom(htItem);
if (cItem != NULL)
{
findMarkEntry(cItem, line);
}
else
{
tvItem.hItem = htItem;
tvItem.mask = TVIF_IMAGE | TVIF_PARAM;
::SendMessage(_treeViewSearchResult.getHSelf(), TVM_GETITEM, 0, reinterpret_cast<LPARAM>(&tvItem));
generic_string *posStr = reinterpret_cast<generic_string *>(tvItem.lParam);
if (posStr)
{
int pos = generic_atoi(posStr->c_str());
if (pos != -1)
{
LONG sci_line = static_cast<LONG>((*_ppEditView)->execute(SCI_LINEFROMPOSITION, pos));
if (line >= sci_line)
{
if (sci_line > _findLine || _findLine == -1)
{
_findLine = sci_line;
_findItem = htItem;
}
}
else
{
if (sci_line < _findEndLine)
_findEndLine = sci_line;
}
}
}
}
}
}
void FunctionListPanel::init(HINSTANCE hInst, HWND hPere, ScintillaEditView **ppEditView)
{
DockingDlgInterface::init(hInst, hPere);
_ppEditView = ppEditView;
bool doLocalConf = (NppParameters::getInstance()).isLocal();
if (!doLocalConf)
{
generic_string funcListXmlPath = (NppParameters::getInstance()).getUserPath();
PathAppend(funcListXmlPath, TEXT("functionList"));
if (!PathFileExists(funcListXmlPath.c_str()))
{
generic_string funcListDefaultXmlPath = (NppParameters::getInstance()).getNppPath();
PathAppend(funcListDefaultXmlPath, TEXT("functionList"));
if (PathFileExists(funcListDefaultXmlPath.c_str()))
{
::CopyFile(funcListDefaultXmlPath.c_str(), funcListXmlPath.c_str(), TRUE);
_funcParserMgr.init(funcListXmlPath, ppEditView);
}
}
else
{
_funcParserMgr.init(funcListXmlPath, ppEditView);
}
}
else
{
generic_string funcListDefaultXmlPath = (NppParameters::getInstance()).getNppPath();
PathAppend(funcListDefaultXmlPath, TEXT("functionList"));
if (PathFileExists(funcListDefaultXmlPath.c_str()))
{
_funcParserMgr.init(funcListDefaultXmlPath, ppEditView);
}
}
}
bool FunctionListPanel::openSelection(const TreeView & treeView)
{
TVITEM tvItem;
tvItem.mask = TVIF_IMAGE | TVIF_PARAM;
tvItem.hItem = treeView.getSelection();
::SendMessage(treeView.getHSelf(), TVM_GETITEM, 0, reinterpret_cast<LPARAM>(&tvItem));
if (tvItem.iImage == INDEX_ROOT || tvItem.iImage == INDEX_NODE)
{
return false;
}
generic_string *posStr = reinterpret_cast<generic_string *>(tvItem.lParam);
if (!posStr)
return false;
int pos = generic_atoi(posStr->c_str());
if (pos == -1)
return false;
auto sci_line = (*_ppEditView)->execute(SCI_LINEFROMPOSITION, pos);
(*_ppEditView)->execute(SCI_ENSUREVISIBLE, sci_line);
(*_ppEditView)->scrollPosToCenter(pos);
return true;
}
void FunctionListPanel::notified(LPNMHDR notification)
{
if (notification->code == TTN_GETDISPINFO)
{
LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)notification;
lpttt->hinst = NULL;
if (notification->idFrom == IDC_SORTBUTTON_FUNCLIST)
{
wcscpy_s(lpttt->szText, _sortTipStr.c_str());
}
else if (notification->idFrom == IDC_RELOADBUTTON_FUNCLIST)
{
wcscpy_s(lpttt->szText, _reloadTipStr.c_str());
}
}
else if (notification->hwndFrom == _treeView.getHSelf() || notification->hwndFrom == this->_treeViewSearchResult.getHSelf())
{
const TreeView & treeView = notification->hwndFrom == _treeView.getHSelf()?_treeView:_treeViewSearchResult;
switch (notification->code)
{
case NM_DBLCLK:
{
openSelection(treeView);
PostMessage(_hParent, WM_COMMAND, SCEN_SETFOCUS << 16, reinterpret_cast<LPARAM>((*_ppEditView)->getHSelf()));
}
break;
case NM_RETURN:
SetWindowLongPtr(_hSelf, DWLP_MSGRESULT, 1); // remove beep
break;
case TVN_KEYDOWN:
{
LPNMTVKEYDOWN ptvkd = (LPNMTVKEYDOWN)notification;
if (ptvkd->wVKey == VK_RETURN)
{
if (!openSelection(treeView))
{
HTREEITEM hItem = treeView.getSelection();
treeView.toggleExpandCollapse(hItem);
break;
}
PostMessage(_hParent, WM_COMMAND, SCEN_SETFOCUS << 16, reinterpret_cast<LPARAM>((*_ppEditView)->getHSelf()));
}
else if (ptvkd->wVKey == VK_TAB)
{
::SetFocus(_hSearchEdit);
SetWindowLongPtr(_hSelf, DWLP_MSGRESULT, 1); // remove beep
}
else if (ptvkd->wVKey == VK_ESCAPE)
{
SetWindowLongPtr(_hSelf, DWLP_MSGRESULT, 1); // remove beep
PostMessage(_hParent, WM_COMMAND, SCEN_SETFOCUS << 16, reinterpret_cast<LPARAM>((*_ppEditView)->getHSelf()));
}
}
break;
}
}
else if (notification->code == DMN_SWITCHIN)
{
reload();
}
else if (notification->code == DMN_CLOSE)
{
::SendMessage(_hParent, WM_COMMAND, IDM_VIEW_FUNC_LIST, 0);
}
}
BOOL FunctionListPanel::setTreeViewImageList(int root_id, int node_id, int leaf_id)
{
HBITMAP hbmp;
COLORREF maskColour = RGB(192, 192, 192);
const int nbBitmaps = 3;
// Creation of image list
if ((_hTreeViewImaLst = ImageList_Create(CX_BITMAP, CY_BITMAP, ILC_COLOR32 | ILC_MASK, nbBitmaps, 0)) == NULL)
return FALSE;
// Add the bmp in the list
hbmp = LoadBitmap(_hInst, MAKEINTRESOURCE(root_id));
if (hbmp == NULL)
return FALSE;
ImageList_AddMasked(_hTreeViewImaLst, hbmp, maskColour);
DeleteObject(hbmp);
hbmp = LoadBitmap(_hInst, MAKEINTRESOURCE(node_id));
if (hbmp == NULL)
return FALSE;
ImageList_AddMasked(_hTreeViewImaLst, hbmp, maskColour);
DeleteObject(hbmp);
hbmp = LoadBitmap(_hInst, MAKEINTRESOURCE(leaf_id));
if (hbmp == NULL)
return FALSE;
ImageList_AddMasked(_hTreeViewImaLst, hbmp, maskColour);
DeleteObject(hbmp);
if (ImageList_GetImageCount(_hTreeViewImaLst) < nbBitmaps)
return FALSE;
// Set image list to the tree view
TreeView_SetImageList(_treeView.getHSelf(), _hTreeViewImaLst, TVSIL_NORMAL);
TreeView_SetImageList(_treeViewSearchResult.getHSelf(), _hTreeViewImaLst, TVSIL_NORMAL);
return TRUE;
}
void FunctionListPanel::searchFuncAndSwitchView()
{
TCHAR text2search[MAX_PATH] ;
::SendMessage(_hSearchEdit, WM_GETTEXT, MAX_PATH, reinterpret_cast<LPARAM>(text2search));
bool doSort = shouldSort();
if (text2search[0] == '\0')
{
_treeViewSearchResult.display(false);
_treeView.display(true);
_pTreeView = &_treeView;
}
else
{
if (_treeView.getRoot() == NULL)
return;
_treeViewSearchResult.removeAllItems();
const TCHAR *fn = ((*_ppEditView)->getCurrentBuffer())->getFileName();
generic_string* invalidValueStr = new generic_string(TEXT("-1"));
posStrs.push_back(invalidValueStr);
LPARAM lParamInvalidPosStr = reinterpret_cast<LPARAM>(invalidValueStr);
_treeViewSearchResult.addItem(fn, NULL, INDEX_ROOT, lParamInvalidPosStr);
_treeView.searchLeafAndBuildTree(_treeViewSearchResult, text2search, INDEX_LEAF);
_treeViewSearchResult.display(true);
_treeViewSearchResult.expand(_treeViewSearchResult.getRoot());
_treeView.display(false);
_pTreeView = &_treeViewSearchResult;
// invalidate the editor rect
::InvalidateRect(_hSearchEdit, NULL, TRUE);
}
if (doSort)
_pTreeView->sort(_pTreeView->getRoot(), true);
}
static WNDPROC oldFunclstToolbarProc = NULL;
static LRESULT CALLBACK funclstToolbarProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CTLCOLOREDIT :
{
return ::SendMessage(::GetParent(hwnd), WM_CTLCOLOREDIT, wParam, lParam);
}
}
return oldFunclstToolbarProc(hwnd, message, wParam, lParam);
}
static WNDPROC oldFunclstSearchEditProc = NULL;
static LRESULT CALLBACK funclstSearchEditProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CHAR:
{
if (wParam == VK_ESCAPE)
{
::SendMessage(hwnd, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(TEXT("")));
return FALSE;
}
else if (wParam == VK_TAB)
{
::SendMessage(GetParent(hwnd), WM_COMMAND, VK_TAB, 1);
return FALSE;
}
}
}
return oldFunclstSearchEditProc(hwnd, message, wParam, lParam);
}
bool FunctionListPanel::shouldSort()
{
TBBUTTONINFO tbbuttonInfo;
tbbuttonInfo.cbSize = sizeof(TBBUTTONINFO);
tbbuttonInfo.dwMask = TBIF_STATE;
::SendMessage(_hToolbarMenu, TB_GETBUTTONINFO, IDC_SORTBUTTON_FUNCLIST, reinterpret_cast<LPARAM>(&tbbuttonInfo));
return (tbbuttonInfo.fsState & TBSTATE_CHECKED) != 0;
}
void FunctionListPanel::setSort(bool isEnabled)
{
TBBUTTONINFO tbbuttonInfo;
tbbuttonInfo.cbSize = sizeof(TBBUTTONINFO);
tbbuttonInfo.dwMask = TBIF_STATE;
tbbuttonInfo.fsState = isEnabled ? TBSTATE_ENABLED | TBSTATE_CHECKED : TBSTATE_ENABLED;
::SendMessage(_hToolbarMenu, TB_SETBUTTONINFO, IDC_SORTBUTTON_FUNCLIST, reinterpret_cast<LPARAM>(&tbbuttonInfo));
}
INT_PTR CALLBACK FunctionListPanel::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
// Make edit field red if not found
case WM_CTLCOLOREDIT :
{
// if the text not found modify the background color of the editor
static HBRUSH hBrushBackground = CreateSolidBrush(BCKGRD_COLOR);
TCHAR text2search[MAX_PATH] ;
::SendMessage(_hSearchEdit, WM_GETTEXT, MAX_PATH, reinterpret_cast<LPARAM>(text2search));
if (text2search[0] == '\0')
{
return FALSE; // no text, use the default color
}
HTREEITEM searchViewRoot = _treeViewSearchResult.getRoot();
if (searchViewRoot)
{
if (_treeViewSearchResult.getChildFrom(searchViewRoot))
return FALSE; // children on root found, use the default color
}
else
return FALSE; // no root (no parser), use the default color
// text not found
SetTextColor((HDC)wParam, TXT_COLOR);
SetBkColor((HDC)wParam, BCKGRD_COLOR);
return (LRESULT)hBrushBackground;
}
case WM_INITDIALOG :
{
int editWidth = NppParameters::getInstance()._dpiManager.scaleX(100);
int editWidthSep = NppParameters::getInstance()._dpiManager.scaleX(105); //editWidth + 5
int editHeight = NppParameters::getInstance()._dpiManager.scaleY(20);
// Create toolbar menu
int style = WS_CHILD | WS_VISIBLE | CCS_ADJUSTABLE | TBSTYLE_AUTOSIZE | TBSTYLE_FLAT | TBSTYLE_LIST | TBSTYLE_TRANSPARENT | BTNS_AUTOSIZE | BTNS_SEP | TBSTYLE_TOOLTIPS;
_hToolbarMenu = CreateWindowEx(0,TOOLBARCLASSNAME,NULL, style,
0,0,0,0,_hSelf,nullptr, _hInst, NULL);
oldFunclstToolbarProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(_hToolbarMenu, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(funclstToolbarProc)));
TBBUTTON tbButtons[3];
// Add the bmap image into toolbar's imagelist
TBADDBITMAP addbmp = {_hInst, 0};
addbmp.nID = IDI_FUNCLIST_SORTBUTTON;
::SendMessage(_hToolbarMenu, TB_ADDBITMAP, 1, reinterpret_cast<LPARAM>(&addbmp));
addbmp.nID = IDI_FUNCLIST_RELOADBUTTON;
::SendMessage(_hToolbarMenu, TB_ADDBITMAP, 1, reinterpret_cast<LPARAM>(&addbmp));
// Place holder of search text field
tbButtons[0].idCommand = 0;
tbButtons[0].iBitmap = editWidthSep;
tbButtons[0].fsState = TBSTATE_ENABLED;
tbButtons[0].fsStyle = BTNS_SEP; //This is just a separator (blank space)
tbButtons[0].iString = 0;
tbButtons[1].idCommand = IDC_SORTBUTTON_FUNCLIST;
tbButtons[1].iBitmap = 0;
tbButtons[1].fsState = TBSTATE_ENABLED;
tbButtons[1].fsStyle = BTNS_CHECK | BTNS_AUTOSIZE;
tbButtons[1].iString = reinterpret_cast<INT_PTR>(TEXT(""));
tbButtons[2].idCommand = IDC_RELOADBUTTON_FUNCLIST;
tbButtons[2].iBitmap = 1;
tbButtons[2].fsState = TBSTATE_ENABLED;
tbButtons[2].fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE;
tbButtons[2].iString = reinterpret_cast<INT_PTR>(TEXT(""));
::SendMessage(_hToolbarMenu, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
::SendMessage(_hToolbarMenu, TB_SETBUTTONSIZE, 0, MAKELONG(16, 16));
::SendMessage(_hToolbarMenu, TB_ADDBUTTONS, sizeof(tbButtons) / sizeof(TBBUTTON), reinterpret_cast<LPARAM>(&tbButtons));
::SendMessage(_hToolbarMenu, TB_AUTOSIZE, 0, 0);
ShowWindow(_hToolbarMenu, SW_SHOW);
// tips text for toolbar buttons
NativeLangSpeaker *pNativeSpeaker = (NppParameters::getInstance()).getNativeLangSpeaker();
_sortTipStr = pNativeSpeaker->getAttrNameStr(_sortTipStr.c_str(), FL_FUCTIONLISTROOTNODE, FL_SORTLOCALNODENAME);
_reloadTipStr = pNativeSpeaker->getAttrNameStr(_reloadTipStr.c_str(), FL_FUCTIONLISTROOTNODE, FL_RELOADLOCALNODENAME);
_hSearchEdit = CreateWindowEx(0, L"Edit", NULL,
WS_CHILD | WS_BORDER | WS_VISIBLE | ES_AUTOVSCROLL,
2, 2, editWidth, editHeight,
_hToolbarMenu, reinterpret_cast<HMENU>(IDC_SEARCHFIELD_FUNCLIST), _hInst, 0 );
oldFunclstSearchEditProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(_hSearchEdit, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(funclstSearchEditProc)));
HFONT hf = (HFONT)::GetStockObject(DEFAULT_GUI_FONT);
if (hf)
::SendMessage(_hSearchEdit, WM_SETFONT, reinterpret_cast<WPARAM>(hf), MAKELPARAM(TRUE, 0));
_treeViewSearchResult.init(_hInst, _hSelf, IDC_LIST_FUNCLIST_AUX);
_treeView.init(_hInst, _hSelf, IDC_LIST_FUNCLIST);
_treeView.makeLabelEditable(false);
setTreeViewImageList(IDI_FUNCLIST_ROOT, IDI_FUNCLIST_NODE, IDI_FUNCLIST_LEAF);
_treeView.display();
return TRUE;
}
case WM_DESTROY:
_treeView.destroy();
_treeViewSearchResult.destroy();
::DestroyWindow(_hToolbarMenu);
break;
case WM_COMMAND :
{
if (HIWORD(wParam) == EN_CHANGE)
{
switch (LOWORD(wParam))
{
case IDC_SEARCHFIELD_FUNCLIST:
{
searchFuncAndSwitchView();
return TRUE;
}
}
}
else if (wParam == VK_TAB)
{
if (_treeViewSearchResult.isVisible())
::SetFocus(_treeViewSearchResult.getHSelf());
else
::SetFocus(_treeView.getHSelf());
return TRUE;
}
switch (LOWORD(wParam))
{
case IDC_SORTBUTTON_FUNCLIST:
{
sortOrUnsort();
}
return TRUE;
case IDC_RELOADBUTTON_FUNCLIST:
{
reload();
}
return TRUE;
}
}
break;
case WM_NOTIFY:
{
notified((LPNMHDR)lParam);
}
return TRUE;
case WM_SIZE:
{
int width = LOWORD(lParam);
int height = HIWORD(lParam);
int extraValue = NppParameters::getInstance()._dpiManager.scaleX(4);
RECT toolbarMenuRect;
::GetClientRect(_hToolbarMenu, &toolbarMenuRect);
::MoveWindow(_hToolbarMenu, 0, 0, width, toolbarMenuRect.bottom, TRUE);
HWND hwnd = _treeView.getHSelf();
if (hwnd)
::MoveWindow(hwnd, 0, toolbarMenuRect.bottom + extraValue, width, height - toolbarMenuRect.bottom - extraValue, TRUE);
HWND hwnd_aux = _treeViewSearchResult.getHSelf();
if (hwnd_aux)
::MoveWindow(hwnd_aux, 0, toolbarMenuRect.bottom + extraValue, width, height - toolbarMenuRect.bottom - extraValue, TRUE);
break;
}
default :
return DockingDlgInterface::run_dlgProc(message, wParam, lParam);
}
return DockingDlgInterface::run_dlgProc(message, wParam, lParam);
}