Apply tab colors to document list items

and add groups to document list.

Fix #12155, fix #12689, cllose #13080
This commit is contained in:
ozone10 2023-02-10 18:03:27 +01:00 committed by Don Ho
parent 0c704fd66b
commit 37963ea21a
14 changed files with 356 additions and 48 deletions

View File

@ -1429,6 +1429,7 @@ Do you want to save your changes before switching themes?"/> <!-- HowToReproduce
<ColumnName name="Name"/>
<ColumnExt name="Ext."/>
<ColumnPath name="Path"/>
<ListGroups name="Group by View"/>
</DocList>
<WindowsDlg>
<ColumnName name="Name"/>

View File

@ -4618,6 +4618,12 @@ void Notepad_plus::docGotoAnotherEditView(FileTransferMode mode)
{
command(IDM_VIEW_MONITORING);
}
if (_pDocumentListPanel != nullptr)
{
Buffer* buf = MainFileManager.getBufferByID(current);
_pDocumentListPanel->setItemColor(buf);
}
}
bool Notepad_plus::activateBuffer(BufferID id, int whichOne, bool forceApplyHilite)
@ -5379,14 +5385,14 @@ void Notepad_plus::getTaskListInfo(TaskListInfo *tli)
BufferID bufID = _pDocTab->getBufferByIndex(i);
Buffer * b = MainFileManager.getBufferByID(bufID);
int status = b->isMonitoringOn()?tb_monitored:(b->isReadOnly()?tb_ro:(b->isDirty()?tb_unsaved:tb_saved));
tli->_tlfsLst.push_back(TaskLstFnStatus(currentView(), i, b->getFullPathName(), status, (void *)bufID));
tli->_tlfsLst.push_back(TaskLstFnStatus(currentView(), i, b->getFullPathName(), status, (void *)bufID, b->getDocColorId()));
}
for (int i = 0 ; i < nonCurrentNbDoc ; ++i)
{
BufferID bufID = _pNonDocTab->getBufferByIndex(i);
Buffer * b = MainFileManager.getBufferByID(bufID);
int status = b->isMonitoringOn()?tb_monitored:(b->isReadOnly()?tb_ro:(b->isDirty()?tb_unsaved:tb_saved));
tli->_tlfsLst.push_back(TaskLstFnStatus(otherView(), i, b->getFullPathName(), status, (void *)bufID));
tli->_tlfsLst.push_back(TaskLstFnStatus(otherView(), i, b->getFullPathName(), status, (void *)bufID, b->getDocColorId()));
}
}
@ -5972,7 +5978,7 @@ void Notepad_plus::getCurrentOpenedFiles(Session & session, bool includUntitledD
sessionFileInfo sfi(buf->getFullPathName(), langName, buf->getEncoding(), buf->getUserReadOnly(), buf->getPosition(editView), buf->getBackupFileName().c_str(), buf->getLastModifiedTimestamp(), buf->getMapPosition());
sfi._isMonitoring = buf->isMonitoringOn();
sfi._individualTabColour = docTab[0]->getIndividualTabColour(static_cast<int>(i));
sfi._individualTabColour = docTab[k]->getIndividualTabColour(static_cast<int>(i));
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, buf->getDocument());
size_t maxLine = static_cast<size_t>(_invisibleEditView.execute(SCI_GETLINECOUNT));

View File

@ -999,7 +999,12 @@ void Notepad_plus::command(int id)
const auto current_index = _pDocTab->getCurrentTabIndex();
BufferID buffer_id = _pDocTab->getBufferByIndex(current_index);
_pDocTab->setIndividualTabColour(buffer_id, color_id);
::SendMessage(_pPublicInterface->getHSelf(), WM_SIZE, 0, 0);
_pDocTab->redraw();
if (_pDocumentListPanel != nullptr)
{
_pDocumentListPanel->setItemColor(buffer_id);
}
}
break;
@ -3112,11 +3117,13 @@ void Notepad_plus::command(int id)
case IDM_VIEW_GOTO_ANOTHER_VIEW:
docGotoAnotherEditView(TransferMove);
checkSyncState();
::SendMessage(_pPublicInterface->getHSelf(), WM_SIZE, 0, 0);
break;
case IDM_VIEW_CLONE_TO_ANOTHER_VIEW:
docGotoAnotherEditView(TransferClone);
checkSyncState();
::SendMessage(_pPublicInterface->getHSelf(), WM_SIZE, 0, 0);
break;
case IDM_VIEW_GOTO_NEW_INSTANCE :

View File

@ -2288,6 +2288,8 @@ bool Notepad_plus::loadSession(Session & session, bool isSnapshotMode, bool shou
if (isSnapshotMode && session._subViewFiles[k]._backupFilePath != TEXT("") && PathFileExists(session._subViewFiles[k]._backupFilePath.c_str()))
buf->setDirty(true);
_subDocTab.setIndividualTabColour(lastOpened, session._subViewFiles[k]._individualTabColour);
//Force in the document so we can add the markers
//Don't use default methods because of performance
Document prevDoc = _subEditView.execute(SCI_GETDOCPOINTER);

View File

@ -4514,6 +4514,18 @@ void NppParameters::feedGUIParameters(TiXmlNode *node)
if (nullptr == nm)
continue;
auto parseYesNoBoolAttribute = [&element](const TCHAR* name, bool defaultValue = false) -> bool {
const TCHAR* val = element->Attribute(name);
if (val != nullptr)
{
if (!lstrcmp(val, TEXT("yes")))
return true;
else if (!lstrcmp(val, TEXT("no")))
return false;
}
return defaultValue;
};
if (!lstrcmp(nm, TEXT("ToolBar")))
{
const TCHAR* val = element->Attribute(TEXT("visible"));
@ -5765,18 +5777,6 @@ void NppParameters::feedGUIParameters(TiXmlNode *node)
val = 0;
_nppGUI._multiInstSetting = (MultiInstSetting)val;
auto parseYesNoBoolAttribute = [&element](const TCHAR* name, bool defaultValue = false) -> bool {
const TCHAR* val = element->Attribute(name);
if (val != nullptr)
{
if (!lstrcmp(val, TEXT("yes")))
return true;
else if (!lstrcmp(val, TEXT("no")))
return false;
}
return defaultValue;
};
_nppGUI._clipboardHistoryPanelKeepState = parseYesNoBoolAttribute(TEXT("clipboardHistory"));
_nppGUI._docListKeepState = parseYesNoBoolAttribute(TEXT("documentList"));
_nppGUI._charPanelKeepState = parseYesNoBoolAttribute(TEXT("characterPanel"));
@ -5847,6 +5847,8 @@ void NppParameters::feedGUIParameters(TiXmlNode *node)
if (element->Attribute(TEXT("fileSwitcherPathWidth"), &i))
_nppGUI._fileSwitcherPathWidth = i;
_nppGUI._fileSwitcherDisableListViewGroups = parseYesNoBoolAttribute(TEXT("fileSwitcherNoGroups"));
const TCHAR * optNameBackSlashEscape = element->Attribute(TEXT("backSlashIsEscapeCharacterForSql"));
if (optNameBackSlashEscape && !lstrcmp(optNameBackSlashEscape, TEXT("no")))
_nppGUI._backSlashIsEscapeCharacterForSql = false;
@ -7167,10 +7169,16 @@ void NppParameters::createXmlTreeFromGUIParams()
TiXmlElement *GUIConfigElement = (newGUIRoot->InsertEndChild(TiXmlElement(TEXT("GUIConfig"))))->ToElement();
GUIConfigElement->SetAttribute(TEXT("name"), TEXT("MISC"));
auto setYesNoBoolAttribute = [&GUIConfigElement](const TCHAR* name, bool value) -> void {
const TCHAR* pStr = value ? TEXT("yes") : TEXT("no");
GUIConfigElement->SetAttribute(name, pStr);
};
GUIConfigElement->SetAttribute(TEXT("fileSwitcherWithoutExtColumn"), _nppGUI._fileSwitcherWithoutExtColumn ? TEXT("yes") : TEXT("no"));
GUIConfigElement->SetAttribute(TEXT("fileSwitcherExtWidth"), _nppGUI._fileSwitcherExtWidth);
GUIConfigElement->SetAttribute(TEXT("fileSwitcherWithoutPathColumn"), _nppGUI._fileSwitcherWithoutPathColumn ? TEXT("yes") : TEXT("no"));
GUIConfigElement->SetAttribute(TEXT("fileSwitcherPathWidth"), _nppGUI._fileSwitcherPathWidth);
setYesNoBoolAttribute(TEXT("fileSwitcherNoGroups"), _nppGUI._fileSwitcherDisableListViewGroups);
GUIConfigElement->SetAttribute(TEXT("backSlashIsEscapeCharacterForSql"), _nppGUI._backSlashIsEscapeCharacterForSql ? TEXT("yes") : TEXT("no"));
GUIConfigElement->SetAttribute(TEXT("writeTechnologyEngine"), _nppGUI._writeTechnologyEngine);
GUIConfigElement->SetAttribute(TEXT("isFolderDroppedOpenFiles"), _nppGUI._isFolderDroppedOpenFiles ? TEXT("yes") : TEXT("no"));

View File

@ -894,10 +894,11 @@ struct NppGUI final
bool _docMapKeepState = false;
bool _funcListKeepState = false;
bool _pluginPanelKeepState = false;
bool _fileSwitcherWithoutExtColumn = true;
bool _fileSwitcherWithoutExtColumn = false;
int _fileSwitcherExtWidth = 50;
bool _fileSwitcherWithoutPathColumn = true;
int _fileSwitcherPathWidth = 50;
bool _fileSwitcherDisableListViewGroups = false;
bool isSnapshotMode() const {return _isSnapshotMode && _rememberLastSession && !_isCmdlineNosessionActivated;};
bool _isSnapshotMode = true;
size_t _snapshotBackupTiming = 7000;

View File

@ -320,6 +320,14 @@ public:
bool allowSmartHilite() const;
bool allowClickableLink() const;
void setDocColorId(int idx) {
_docColorId = idx;
};
int getDocColorId() {
return _docColorId;
};
private:
int indexOfReference(const ScintillaEditView * identifier) const;
@ -369,6 +377,8 @@ private:
long _recentTag = -1;
static long _recentTagCtr;
int _docColorId = -1;
// For backup system
generic_string _backupFileName;
bool _isModified = false;

View File

@ -33,7 +33,7 @@ void DocTabView::addBuffer(BufferID buffer)
if (getIndexByBuffer(buffer) != -1) //no duplicates
return;
Buffer * buf = MainFileManager.getBufferByID(buffer);
TCITEM tie;
TCITEM tie{};
tie.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
int index = -1;
@ -58,15 +58,13 @@ void DocTabView::closeBuffer(BufferID buffer)
void DocTabView::setIndividualTabColour(BufferID bufferId, int colorId)
{
_tabIndexToColour[bufferId] = colorId;
bufferId->setDocColorId(colorId);
}
int DocTabView::getIndividualTabColour(int tabIndex)
{
BufferID bufferId = getBufferByIndex(tabIndex);
auto it = _tabIndexToColour.find(bufferId);
if (it != _tabIndexToColour.end()) return it->second;
else return -1;
return bufferId->getDocColorId();
}
bool DocTabView::activateBuffer(BufferID buffer)
@ -89,7 +87,7 @@ BufferID DocTabView::activeBuffer()
BufferID DocTabView::findBufferByName(const TCHAR * fullfilename) //-1 if not found, something else otherwise
{
TCITEM tie;
TCITEM tie{};
tie.lParam = -1;
tie.mask = TCIF_PARAM;
for (size_t i = 0; i < _nbItem; ++i)
@ -108,7 +106,7 @@ BufferID DocTabView::findBufferByName(const TCHAR * fullfilename) //-1 if not fo
int DocTabView::getIndexByBuffer(BufferID id)
{
TCITEM tie;
TCITEM tie{};
tie.lParam = -1;
tie.mask = TCIF_PARAM;
for (size_t i = 0; i < _nbItem; ++i)
@ -123,7 +121,7 @@ int DocTabView::getIndexByBuffer(BufferID id)
BufferID DocTabView::getBufferByIndex(size_t index)
{
TCITEM tie;
TCITEM tie{};
tie.lParam = -1;
tie.mask = TCIF_PARAM;
::SendMessage(_hSelf, TCM_GETITEM, index, reinterpret_cast<LPARAM>(&tie));
@ -138,7 +136,7 @@ void DocTabView::bufferUpdated(Buffer * buffer, int mask)
if (index == -1)
return;
TCITEM tie;
TCITEM tie{};
tie.lParam = -1;
tie.mask = 0;
@ -157,7 +155,7 @@ void DocTabView::bufferUpdated(Buffer * buffer, int mask)
}
//We must make space for the added ampersand characters.
TCHAR encodedLabel[2 * MAX_PATH];
TCHAR encodedLabel[2 * MAX_PATH] = { '\0' };
if (mask & BufferChangeFilename)
{
@ -200,7 +198,7 @@ void DocTabView::setBuffer(size_t index, BufferID id)
if (index < 0 || index >= _nbItem)
return;
TCITEM tie;
TCITEM tie{};
tie.lParam = reinterpret_cast<LPARAM>(id);
tie.mask = TCIF_PARAM;
::SendMessage(_hSelf, TCM_SETITEM, index, reinterpret_cast<LPARAM>(&tie));

View File

@ -97,7 +97,6 @@ private :
ScintillaEditView *_pView = nullptr;
static bool _hideTabBarStatus;
std::map<BufferID, int> _tabIndexToColour;
std::vector<IconList *> _pIconListVector;
int _iconListIndexChoice = -1;
};

View File

@ -32,9 +32,10 @@ struct TaskLstFnStatus {
generic_string _fn;
int _status = 0;
void *_bufID = nullptr;
int _docColor = -1;
TaskLstFnStatus(const generic_string& str, int status) : _fn(str), _status(status){};
TaskLstFnStatus(int iView, int docIndex, generic_string str, int status, void *bufID) :
_iView(iView), _docIndex(docIndex), _fn(str), _status(status), _bufID(bufID) {};
TaskLstFnStatus(int iView, int docIndex, generic_string str, int status, void *bufID, int docColor) :
_iView(iView), _docIndex(docIndex), _fn(str), _status(status), _bufID(bufID), _docColor(docColor) {};
};
struct TaskListInfo {

View File

@ -27,6 +27,10 @@
#define CLMNEXT_ID 1
#define CLMNPATH_ID 2
#define SEP_POS 3
#define LVGROUPS_ID 4
COLORREF VerticalFileSwitcher::_bgColor = 0xFFFFFF;
int CALLBACK ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
@ -83,6 +87,180 @@ void VerticalFileSwitcher::startColumnSort()
updateHeaderArrow();
}
LRESULT VerticalFileSwitcher::listViewNotifyCustomDraw(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
auto lplvcd = reinterpret_cast<LPNMLVCUSTOMDRAW>(lParam);
switch (lplvcd->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
{
if ((lplvcd->dwItemType == LVCDI_GROUP) && NppDarkMode::isThemeDark())
{
RECT rcHeader{};
ListView_GetGroupRect(lplvcd->nmcd.hdr.hwndFrom, lplvcd->nmcd.dwItemSpec, LVGGR_HEADER, &rcHeader);
HBRUSH hBrush = ::CreateSolidBrush(VerticalFileSwitcher::_bgColor);
::FillRect(lplvcd->nmcd.hdc, &rcHeader, hBrush);
::DeleteObject(hBrush);
hBrush = nullptr;
}
return CDRF_NOTIFYITEMDRAW;
}
case CDDS_ITEMPREPAINT:
{
const RECT& rcRow = lplvcd->nmcd.rc;
const bool isThemeDark = NppDarkMode::isThemeDark();
const auto hHeader = ListView_GetHeader(lplvcd->nmcd.hdr.hwndFrom);
const auto colCount = Header_GetItemCount(hHeader);
const LONG paddingLeft = isThemeDark ? 1 : 0;
const LONG paddingRight = isThemeDark ? 2 : 1;
RECT rcSubItem{ rcRow };
RECT rcSubItem2{};
RECT rcSubItem3{};
rcSubItem.right -= paddingRight;
auto setRectForSubItem = [hHeader, paddingLeft, paddingRight](RECT& first, RECT& second, int idxSecond) -> void {
Header_GetItemRect(hHeader, idxSecond, &second);
first.right = second.left - paddingRight;
second.left -= paddingLeft;
second.right -= paddingRight;
second.top = first.top;
second.bottom = first.bottom;
};
if (colCount >= 2)
{
setRectForSubItem(rcSubItem, rcSubItem2, 1);
}
if (colCount == 3)
{
setRectForSubItem(rcSubItem2, rcSubItem3, 2);
}
const auto isSelected = ListView_GetItemState(lplvcd->nmcd.hdr.hwndFrom, lplvcd->nmcd.dwItemSpec, LVIS_SELECTED) == LVIS_SELECTED;
const bool isHot = (lplvcd->nmcd.uItemState & CDIS_HOT) == CDIS_HOT;
const int colorID = reinterpret_cast<TaskLstFnStatus*>(lplvcd->nmcd.lItemlParam)->_docColor;
COLORREF bgColor{0xFFFFFF};
bool applyColor = false;
if (colorID != -1)
{
bgColor = NppDarkMode::getIndividualTabColour(colorID, isThemeDark, false);
applyColor = true;
}
else if (isThemeDark)
{
if (isSelected)
{
bgColor = NppDarkMode::getSofterBackgroundColor();
applyColor = true;
}
else if (isHot)
{
bgColor = NppDarkMode::getHotBackgroundColor();
applyColor = true;
}
}
if (applyColor)
{
if (isThemeDark)
{
lplvcd->clrText = NppDarkMode::getTextColor();
}
lplvcd->clrTextBk = bgColor;
HBRUSH hBrush = ::CreateSolidBrush(bgColor);
::FillRect(lplvcd->nmcd.hdc, &rcSubItem, hBrush);
if (colCount >= 2)
{
::FillRect(lplvcd->nmcd.hdc, &rcSubItem2, hBrush);
}
if (colCount == 3)
{
::FillRect(lplvcd->nmcd.hdc, &rcSubItem3, hBrush);
}
::DeleteObject(hBrush);
hBrush = nullptr;
}
if (isSelected)
{
::DrawFocusRect(lplvcd->nmcd.hdc, &rcRow);
}
else if (isHot)
{
::FrameRect(lplvcd->nmcd.hdc, &rcRow, isThemeDark ? NppDarkMode::getHotEdgeBrush() : ::GetSysColorBrush(COLOR_WINDOWTEXT));
}
return CDRF_NEWFONT;
}
default:
break;
}
return ::DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK VerticalFileSwitcher::FileSwitcherNotifySubclass(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
UINT_PTR uIdSubclass,
DWORD_PTR /*dwRefData*/
)
{
switch (uMsg)
{
case WM_NCDESTROY:
{
::RemoveWindowSubclass(hWnd, VerticalFileSwitcher::FileSwitcherNotifySubclass, uIdSubclass);
break;
}
case WM_NOTIFY:
{
auto nmhdr = reinterpret_cast<LPNMHDR>(lParam);
switch (nmhdr->code)
{
case NM_CUSTOMDRAW:
{
constexpr size_t classNameLen = 16;
wchar_t className[classNameLen]{};
GetClassName(nmhdr->hwndFrom, className, classNameLen);
if (wcscmp(className, WC_LISTVIEW) == 0)
{
return VerticalFileSwitcher::listViewNotifyCustomDraw(hWnd, uMsg, wParam, lParam);
}
break;
}
}
break;
}
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
void VerticalFileSwitcher::autoSubclassWindowNotify(HWND hParent)
{
::SetWindowSubclass(hParent, VerticalFileSwitcher::FileSwitcherNotifySubclass, _fileSwitcherNotifySubclassID, 0);
}
intptr_t CALLBACK VerticalFileSwitcher::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
@ -99,7 +277,7 @@ intptr_t CALLBACK VerticalFileSwitcher::run_dlgProc(UINT message, WPARAM wParam,
_defaultListViewProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(_fileListView.getHSelf(), GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(listViewStaticProc)));
NppDarkMode::autoSubclassAndThemeChildControls(_hSelf);
NppDarkMode::autoSubclassAndThemeWindowNotify(_hSelf);
VerticalFileSwitcher::autoSubclassWindowNotify(_hSelf);
return TRUE;
}
@ -182,7 +360,7 @@ intptr_t CALLBACK VerticalFileSwitcher::run_dlgProc(UINT message, WPARAM wParam,
LVITEM item{};
item.mask = LVIF_PARAM;
item.iItem = i;
item.iItem = i;
ListView_GetItem(((LPNMHDR)lParam)->hwndFrom, &item);
TaskLstFnStatus *tlfs = (TaskLstFnStatus *)item.lParam;
@ -211,7 +389,7 @@ intptr_t CALLBACK VerticalFileSwitcher::run_dlgProc(UINT message, WPARAM wParam,
LVITEM item{};
item.mask = LVIF_PARAM;
item.iItem = i;
item.iItem = i;
ListView_GetItem(((LPNMHDR)lParam)->hwndFrom, &item);
TaskLstFnStatus *tlfs = (TaskLstFnStatus *)item.lParam;
@ -222,7 +400,7 @@ intptr_t CALLBACK VerticalFileSwitcher::run_dlgProc(UINT message, WPARAM wParam,
{
// Redirect NM_RCLICK message to Notepad_plus handle
NMHDR nmhdr{};
nmhdr.code = NM_RCLICK;
nmhdr.code = reinterpret_cast<LPNMHDR>(lParam)->code; //NM_RCLICK
nmhdr.hwndFrom = _hSelf;
nmhdr.idFrom = ::GetDlgCtrlID(nmhdr.hwndFrom);
::SendMessage(_hParent, WM_NOTIFY, nmhdr.idFrom, reinterpret_cast<LPARAM>(&nmhdr));
@ -357,15 +535,20 @@ void VerticalFileSwitcher::initPopupMenus()
generic_string extStr = pNativeSpeaker->getAttrNameStr(TEXT("Ext."), FS_ROOTNODE, FS_CLMNEXT);
generic_string pathStr = pNativeSpeaker->getAttrNameStr(TEXT("Path"), FS_ROOTNODE, FS_CLMNPATH);
generic_string groupStr = pNativeSpeaker->getAttrNameStr(TEXT("Group by View"), FS_ROOTNODE, FS_LVGROUPS);
_hGlobalMenu = ::CreatePopupMenu();
::InsertMenu(_hGlobalMenu, 0, MF_BYCOMMAND, CLMNEXT_ID, extStr.c_str());
::InsertMenu(_hGlobalMenu, 0, MF_BYCOMMAND, CLMNPATH_ID, pathStr.c_str());
::InsertMenu(_hGlobalMenu, CLMNEXT_ID, MF_BYCOMMAND | MF_STRING, CLMNEXT_ID, extStr.c_str());
::InsertMenu(_hGlobalMenu, CLMNPATH_ID, MF_BYCOMMAND | MF_STRING, CLMNPATH_ID, pathStr.c_str());
::InsertMenu(_hGlobalMenu, SEP_POS, MF_BYCOMMAND | MF_SEPARATOR, 0, nullptr);
::InsertMenu(_hGlobalMenu, LVGROUPS_ID, MF_BYCOMMAND | MF_STRING, LVGROUPS_ID, groupStr.c_str());
bool isExtColumn = nppGUI._fileSwitcherWithoutExtColumn;
::CheckMenuItem(_hGlobalMenu, CLMNEXT_ID, MF_BYCOMMAND | (isExtColumn ? MF_UNCHECKED : MF_CHECKED));
bool isPathColumn = nppGUI._fileSwitcherWithoutPathColumn;
::CheckMenuItem(_hGlobalMenu, CLMNPATH_ID, MF_BYCOMMAND | (isPathColumn ? MF_UNCHECKED : MF_CHECKED));
bool isListViewGroups = nppGUI._fileSwitcherDisableListViewGroups;
::CheckMenuItem(_hGlobalMenu, LVGROUPS_ID, MF_BYCOMMAND | (isListViewGroups ? MF_UNCHECKED : MF_CHECKED));
}
void VerticalFileSwitcher::popupMenuCmd(int cmdID)
@ -388,6 +571,14 @@ void VerticalFileSwitcher::popupMenuCmd(int cmdID)
reload();
}
break;
case LVGROUPS_ID:
{
bool& isListViewGroups = NppParameters::getInstance().getNppGUI()._fileSwitcherDisableListViewGroups;
isListViewGroups = !isListViewGroups;
::CheckMenuItem(_hGlobalMenu, LVGROUPS_ID, MF_BYCOMMAND | (isListViewGroups ? MF_UNCHECKED : MF_CHECKED));
reload();
}
break;
}
}

View File

@ -67,6 +67,10 @@ public:
_fileListView.setItemIconStatus(bufferID) ;
};
void setItemColor(BufferID bufferID) {
_fileListView.setItemColor(bufferID);
};
generic_string getFullFilePath(size_t i) const {
return _fileListView.getFullFilePath(i);
};
@ -81,14 +85,14 @@ public:
std::vector<SwitcherFileInfo> getSelectedFiles(bool reverse = false) const {
return _fileListView.getSelectedFiles(reverse);
};
void startColumnSort();
void reload(){
_fileListView.reload();
startColumnSort();
};
void updateTabOrder(){
if (_lastSortingDirection == SORT_DIRECTION_NONE) {
_fileListView.reload();
@ -97,7 +101,33 @@ public:
virtual void setBackgroundColor(COLORREF bgColour) {
_fileListView.setBackgroundColor(bgColour);
};
auto r = GetRValue(bgColour);
auto g = GetGValue(bgColour);
auto b = GetBValue(bgColour);
constexpr int luminenceIncrementBy = 333; // 33.3 %
// main color is blue
// but difference must be high
// can have similar blue color as header
constexpr int difference = 12;
const auto bAdjusted = static_cast<BYTE>(std::max<int>(0, static_cast<int>(b) - difference));
if (bAdjusted > r && bAdjusted > g)
{
// using values from NppDarkMode.cpp
// from double calculatePerceivedLighness(COLORREF c)
// double luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
// values multiplied by 1024 and then shift result by 10 - "fake" divide by 1024
// for performance
const auto grayscale = static_cast<BYTE>((r * 218 + g * 732 + b * 74) >> 10);
_bgColor = ::ColorAdjustLuma(RGB(grayscale, grayscale, grayscale), luminenceIncrementBy, TRUE);
}
else
{
_bgColor = ::ColorAdjustLuma(bgColour, luminenceIncrementBy, TRUE);
}
};
virtual void setForegroundColor(COLORREF fgColour) {
_fileListView.setForegroundColor(fgColour);
@ -108,8 +138,6 @@ protected:
void initPopupMenus();
void popupMenuCmd(int cmdID);
static LRESULT CALLBACK listViewStaticProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
const auto dlg = (VerticalFileSwitcher*)(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
return (run_listViewProc(dlg->_defaultListViewProc, hwnd, message, wParam, lParam));
@ -121,4 +149,10 @@ private:
VerticalFileSwitcherListView _fileListView;
HIMAGELIST _hImaLst = nullptr;
WNDPROC _defaultListViewProc = nullptr;
static COLORREF _bgColor;
static const UINT_PTR _fileSwitcherNotifySubclassID = 42;
static LRESULT listViewNotifyCustomDraw(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK FileSwitcherNotifySubclass(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
void autoSubclassWindowNotify(HWND hParent);
};

View File

@ -33,7 +33,7 @@ void VerticalFileSwitcherListView::init(HINSTANCE hInst, HWND parent, HIMAGELIST
// Create the list-view window in report view with label editing enabled.
int listViewStyles = LVS_REPORT /*| LVS_SINGLESEL*/ | LVS_AUTOARRANGE\
| LVS_SHAREIMAGELISTS | LVS_SHOWSELALWAYS;
| LVS_SHAREIMAGELISTS | LVS_SHOWSELALWAYS | LVS_ALIGNTOP;
_hSelf = ::CreateWindow(WC_LISTVIEW,
TEXT(""),
@ -54,6 +54,22 @@ void VerticalFileSwitcherListView::init(HINSTANCE hInst, HWND parent, HIMAGELIST
ListView_SetExtendedListViewStyle(_hSelf, LVS_EX_FULLROWSELECT | LVS_EX_BORDERSELECT | LVS_EX_INFOTIP | LVS_EX_DOUBLEBUFFER);
ListView_SetItemCountEx(_hSelf, 50, LVSICF_NOSCROLL);
ListView_SetImageList(_hSelf, _hImaLst, LVSIL_SMALL);
LVGROUP group{};
constexpr size_t headerLen = 1;
wchar_t header[headerLen] = L"";
group.cbSize = sizeof(LVGROUP);
group.mask = LVGF_HEADER | LVGF_GROUPID | LVGF_STATE;
group.pszHeader = header;
group.cchHeader = headerLen;
group.iGroupId = _groupID;
group.state = LVGS_COLLAPSIBLE;
LVGROUP group2 = group;
group2.iGroupId = _group2ID;
ListView_InsertGroup(_hSelf, -1, &group);
ListView_InsertGroup(_hSelf, -1, &group2);
}
void VerticalFileSwitcherListView::destroy()
@ -77,6 +93,9 @@ void VerticalFileSwitcherListView::initList()
NppParameters& nppParams = NppParameters::getInstance();
NativeLangSpeaker *pNativeSpeaker = nppParams.getNativeLangSpeaker();
const bool isListViewGroups = !nppParams.getNppGUI()._fileSwitcherDisableListViewGroups;
ListView_EnableGroupView(_hSelf, isListViewGroups ? TRUE : FALSE);
bool isExtColumn = !nppParams.getNppGUI()._fileSwitcherWithoutExtColumn;
bool isPathColumn = !nppParams.getNppGUI()._fileSwitcherWithoutPathColumn;
@ -111,7 +130,7 @@ void VerticalFileSwitcherListView::initList()
{
TaskLstFnStatus & fileNameStatus = taskListInfo._tlfsLst[i];
TaskLstFnStatus *tl = new TaskLstFnStatus(fileNameStatus._iView, fileNameStatus._docIndex, fileNameStatus._fn, fileNameStatus._status, (void *)fileNameStatus._bufID);
TaskLstFnStatus *tl = new TaskLstFnStatus(fileNameStatus);
TCHAR fn[MAX_PATH] = { '\0' };
wcscpy_s(fn, ::PathFindFileName(fileNameStatus._fn.c_str()));
@ -121,13 +140,14 @@ void VerticalFileSwitcherListView::initList()
::PathRemoveExtension(fn);
}
LVITEM item{};
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_GROUPID;
item.pszText = fn;
item.iItem = static_cast<int32_t>(i);
item.iSubItem = 0;
item.iImage = fileNameStatus._status;
item.lParam = reinterpret_cast<LPARAM>(tl);
item.iGroupId = (fileNameStatus._iView == MAIN_VIEW) ? _groupID : _group2ID;
ListView_InsertItem(_hSelf, &item);
int colIndex = 0;
if (isExtColumn)
@ -229,6 +249,30 @@ void VerticalFileSwitcherListView::setItemIconStatus(BufferID bufferID)
}
}
void VerticalFileSwitcherListView::setItemColor(BufferID bufferID)
{
Buffer* buf = static_cast<Buffer*>(bufferID);
LVITEM item{};
item.mask = LVIF_PARAM;
int nbItem = ListView_GetItemCount(_hSelf);
for (int i = 0; i < nbItem; ++i)
{
item.iItem = i;
ListView_GetItem(_hSelf, &item);
TaskLstFnStatus* tlfs = reinterpret_cast<TaskLstFnStatus*>(item.lParam);
if (tlfs->_bufID == bufferID)
{
tlfs->_docColor = buf->getDocColorId();
ListView_SetItem(_hSelf, &item);
}
}
redraw();
}
generic_string VerticalFileSwitcherListView::getFullFilePath(size_t i) const
{
size_t nbItem = ListView_GetItemCount(_hSelf);
@ -270,7 +314,7 @@ int VerticalFileSwitcherListView::add(BufferID bufferID, int iView)
Buffer *buf = static_cast<Buffer *>(bufferID);
const TCHAR *fileName = buf->getFileName();
NppGUI& nppGUI = NppParameters::getInstance().getNppGUI();
TaskLstFnStatus *tl = new TaskLstFnStatus(iView, 0, buf->getFullPathName(), 0, (void *)bufferID);
TaskLstFnStatus *tl = new TaskLstFnStatus(iView, 0, buf->getFullPathName(), 0, (void *)bufferID, -1);
TCHAR fn[MAX_PATH] = { '\0' };
wcscpy_s(fn, ::PathFindFileName(fileName));
@ -281,13 +325,14 @@ int VerticalFileSwitcherListView::add(BufferID bufferID, int iView)
::PathRemoveExtension(fn);
}
LVITEM item{};
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_GROUPID;
item.pszText = fn;
item.iItem = _currentIndex;
item.iSubItem = 0;
item.iImage = buf->isMonitoringOn()?3:(buf->isReadOnly()?2:(buf->isDirty()?1:0));
item.lParam = reinterpret_cast<LPARAM>(tl);
item.iGroupId = (iView == MAIN_VIEW) ? _groupID : _group2ID;
ListView_InsertItem(_hSelf, &item);
int colIndex = 0;
if (isExtColumn)

View File

@ -31,6 +31,7 @@ typedef Buffer * BufferID; //each buffer has unique ID by which it can be retrie
#define FS_CLMNNAME "ColumnName"
#define FS_CLMNEXT "ColumnExt"
#define FS_CLMNPATH "ColumnPath"
#define FS_LVGROUPS "ListGroups"
struct SwitcherFileInfo {
BufferID _bufID = 0;
@ -58,6 +59,7 @@ public:
void activateItem(BufferID bufferID, int iView);
void setItemIconStatus(BufferID bufferID);
generic_string getFullFilePath(size_t i) const;
void setItemColor(BufferID bufferID);
void insertColumn(const TCHAR *name, int width, int index);
void resizeColumns(int totalWidth);
@ -90,6 +92,9 @@ protected:
int _currentIndex = 0;
static const int _groupID = 1;
static const int _group2ID = 2;
int find(BufferID bufferID, int iView) const;
int add(BufferID bufferID, int iView);
void remove(int index);