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"/> <ColumnName name="Name"/>
<ColumnExt name="Ext."/> <ColumnExt name="Ext."/>
<ColumnPath name="Path"/> <ColumnPath name="Path"/>
<ListGroups name="Group by View"/>
</DocList> </DocList>
<WindowsDlg> <WindowsDlg>
<ColumnName name="Name"/> <ColumnName name="Name"/>

View File

@ -4618,6 +4618,12 @@ void Notepad_plus::docGotoAnotherEditView(FileTransferMode mode)
{ {
command(IDM_VIEW_MONITORING); 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) 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); BufferID bufID = _pDocTab->getBufferByIndex(i);
Buffer * b = MainFileManager.getBufferByID(bufID); Buffer * b = MainFileManager.getBufferByID(bufID);
int status = b->isMonitoringOn()?tb_monitored:(b->isReadOnly()?tb_ro:(b->isDirty()?tb_unsaved:tb_saved)); 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) for (int i = 0 ; i < nonCurrentNbDoc ; ++i)
{ {
BufferID bufID = _pNonDocTab->getBufferByIndex(i); BufferID bufID = _pNonDocTab->getBufferByIndex(i);
Buffer * b = MainFileManager.getBufferByID(bufID); Buffer * b = MainFileManager.getBufferByID(bufID);
int status = b->isMonitoringOn()?tb_monitored:(b->isReadOnly()?tb_ro:(b->isDirty()?tb_unsaved:tb_saved)); 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()); 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._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()); _invisibleEditView.execute(SCI_SETDOCPOINTER, 0, buf->getDocument());
size_t maxLine = static_cast<size_t>(_invisibleEditView.execute(SCI_GETLINECOUNT)); 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(); const auto current_index = _pDocTab->getCurrentTabIndex();
BufferID buffer_id = _pDocTab->getBufferByIndex(current_index); BufferID buffer_id = _pDocTab->getBufferByIndex(current_index);
_pDocTab->setIndividualTabColour(buffer_id, color_id); _pDocTab->setIndividualTabColour(buffer_id, color_id);
::SendMessage(_pPublicInterface->getHSelf(), WM_SIZE, 0, 0); _pDocTab->redraw();
if (_pDocumentListPanel != nullptr)
{
_pDocumentListPanel->setItemColor(buffer_id);
}
} }
break; break;
@ -3112,11 +3117,13 @@ void Notepad_plus::command(int id)
case IDM_VIEW_GOTO_ANOTHER_VIEW: case IDM_VIEW_GOTO_ANOTHER_VIEW:
docGotoAnotherEditView(TransferMove); docGotoAnotherEditView(TransferMove);
checkSyncState(); checkSyncState();
::SendMessage(_pPublicInterface->getHSelf(), WM_SIZE, 0, 0);
break; break;
case IDM_VIEW_CLONE_TO_ANOTHER_VIEW: case IDM_VIEW_CLONE_TO_ANOTHER_VIEW:
docGotoAnotherEditView(TransferClone); docGotoAnotherEditView(TransferClone);
checkSyncState(); checkSyncState();
::SendMessage(_pPublicInterface->getHSelf(), WM_SIZE, 0, 0);
break; break;
case IDM_VIEW_GOTO_NEW_INSTANCE : 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())) if (isSnapshotMode && session._subViewFiles[k]._backupFilePath != TEXT("") && PathFileExists(session._subViewFiles[k]._backupFilePath.c_str()))
buf->setDirty(true); buf->setDirty(true);
_subDocTab.setIndividualTabColour(lastOpened, session._subViewFiles[k]._individualTabColour);
//Force in the document so we can add the markers //Force in the document so we can add the markers
//Don't use default methods because of performance //Don't use default methods because of performance
Document prevDoc = _subEditView.execute(SCI_GETDOCPOINTER); Document prevDoc = _subEditView.execute(SCI_GETDOCPOINTER);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,6 +27,10 @@
#define CLMNEXT_ID 1 #define CLMNEXT_ID 1
#define CLMNPATH_ID 2 #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) int CALLBACK ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{ {
@ -83,6 +87,180 @@ void VerticalFileSwitcher::startColumnSort()
updateHeaderArrow(); 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) intptr_t CALLBACK VerticalFileSwitcher::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
{ {
switch (message) 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))); _defaultListViewProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(_fileListView.getHSelf(), GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(listViewStaticProc)));
NppDarkMode::autoSubclassAndThemeChildControls(_hSelf); NppDarkMode::autoSubclassAndThemeChildControls(_hSelf);
NppDarkMode::autoSubclassAndThemeWindowNotify(_hSelf); VerticalFileSwitcher::autoSubclassWindowNotify(_hSelf);
return TRUE; return TRUE;
} }
@ -222,7 +400,7 @@ intptr_t CALLBACK VerticalFileSwitcher::run_dlgProc(UINT message, WPARAM wParam,
{ {
// Redirect NM_RCLICK message to Notepad_plus handle // Redirect NM_RCLICK message to Notepad_plus handle
NMHDR nmhdr{}; NMHDR nmhdr{};
nmhdr.code = NM_RCLICK; nmhdr.code = reinterpret_cast<LPNMHDR>(lParam)->code; //NM_RCLICK
nmhdr.hwndFrom = _hSelf; nmhdr.hwndFrom = _hSelf;
nmhdr.idFrom = ::GetDlgCtrlID(nmhdr.hwndFrom); nmhdr.idFrom = ::GetDlgCtrlID(nmhdr.hwndFrom);
::SendMessage(_hParent, WM_NOTIFY, nmhdr.idFrom, reinterpret_cast<LPARAM>(&nmhdr)); ::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 extStr = pNativeSpeaker->getAttrNameStr(TEXT("Ext."), FS_ROOTNODE, FS_CLMNEXT);
generic_string pathStr = pNativeSpeaker->getAttrNameStr(TEXT("Path"), FS_ROOTNODE, FS_CLMNPATH); 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(); _hGlobalMenu = ::CreatePopupMenu();
::InsertMenu(_hGlobalMenu, 0, MF_BYCOMMAND, CLMNEXT_ID, extStr.c_str()); ::InsertMenu(_hGlobalMenu, CLMNEXT_ID, MF_BYCOMMAND | MF_STRING, CLMNEXT_ID, extStr.c_str());
::InsertMenu(_hGlobalMenu, 0, MF_BYCOMMAND, CLMNPATH_ID, pathStr.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; bool isExtColumn = nppGUI._fileSwitcherWithoutExtColumn;
::CheckMenuItem(_hGlobalMenu, CLMNEXT_ID, MF_BYCOMMAND | (isExtColumn ? MF_UNCHECKED : MF_CHECKED)); ::CheckMenuItem(_hGlobalMenu, CLMNEXT_ID, MF_BYCOMMAND | (isExtColumn ? MF_UNCHECKED : MF_CHECKED));
bool isPathColumn = nppGUI._fileSwitcherWithoutPathColumn; bool isPathColumn = nppGUI._fileSwitcherWithoutPathColumn;
::CheckMenuItem(_hGlobalMenu, CLMNPATH_ID, MF_BYCOMMAND | (isPathColumn ? MF_UNCHECKED : MF_CHECKED)); ::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) void VerticalFileSwitcher::popupMenuCmd(int cmdID)
@ -388,6 +571,14 @@ void VerticalFileSwitcher::popupMenuCmd(int cmdID)
reload(); reload();
} }
break; 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) ; _fileListView.setItemIconStatus(bufferID) ;
}; };
void setItemColor(BufferID bufferID) {
_fileListView.setItemColor(bufferID);
};
generic_string getFullFilePath(size_t i) const { generic_string getFullFilePath(size_t i) const {
return _fileListView.getFullFilePath(i); return _fileListView.getFullFilePath(i);
}; };
@ -97,7 +101,33 @@ public:
virtual void setBackgroundColor(COLORREF bgColour) { virtual void setBackgroundColor(COLORREF bgColour) {
_fileListView.setBackgroundColor(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) { virtual void setForegroundColor(COLORREF fgColour) {
_fileListView.setForegroundColor(fgColour); _fileListView.setForegroundColor(fgColour);
@ -108,8 +138,6 @@ protected:
void initPopupMenus(); void initPopupMenus();
void popupMenuCmd(int cmdID); void popupMenuCmd(int cmdID);
static LRESULT CALLBACK listViewStaticProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static LRESULT CALLBACK listViewStaticProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
const auto dlg = (VerticalFileSwitcher*)(::GetWindowLongPtr(hwnd, GWLP_USERDATA)); const auto dlg = (VerticalFileSwitcher*)(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
return (run_listViewProc(dlg->_defaultListViewProc, hwnd, message, wParam, lParam)); return (run_listViewProc(dlg->_defaultListViewProc, hwnd, message, wParam, lParam));
@ -121,4 +149,10 @@ private:
VerticalFileSwitcherListView _fileListView; VerticalFileSwitcherListView _fileListView;
HIMAGELIST _hImaLst = nullptr; HIMAGELIST _hImaLst = nullptr;
WNDPROC _defaultListViewProc = 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. // Create the list-view window in report view with label editing enabled.
int listViewStyles = LVS_REPORT /*| LVS_SINGLESEL*/ | LVS_AUTOARRANGE\ int listViewStyles = LVS_REPORT /*| LVS_SINGLESEL*/ | LVS_AUTOARRANGE\
| LVS_SHAREIMAGELISTS | LVS_SHOWSELALWAYS; | LVS_SHAREIMAGELISTS | LVS_SHOWSELALWAYS | LVS_ALIGNTOP;
_hSelf = ::CreateWindow(WC_LISTVIEW, _hSelf = ::CreateWindow(WC_LISTVIEW,
TEXT(""), 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_SetExtendedListViewStyle(_hSelf, LVS_EX_FULLROWSELECT | LVS_EX_BORDERSELECT | LVS_EX_INFOTIP | LVS_EX_DOUBLEBUFFER);
ListView_SetItemCountEx(_hSelf, 50, LVSICF_NOSCROLL); ListView_SetItemCountEx(_hSelf, 50, LVSICF_NOSCROLL);
ListView_SetImageList(_hSelf, _hImaLst, LVSIL_SMALL); 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() void VerticalFileSwitcherListView::destroy()
@ -77,6 +93,9 @@ void VerticalFileSwitcherListView::initList()
NppParameters& nppParams = NppParameters::getInstance(); NppParameters& nppParams = NppParameters::getInstance();
NativeLangSpeaker *pNativeSpeaker = nppParams.getNativeLangSpeaker(); NativeLangSpeaker *pNativeSpeaker = nppParams.getNativeLangSpeaker();
const bool isListViewGroups = !nppParams.getNppGUI()._fileSwitcherDisableListViewGroups;
ListView_EnableGroupView(_hSelf, isListViewGroups ? TRUE : FALSE);
bool isExtColumn = !nppParams.getNppGUI()._fileSwitcherWithoutExtColumn; bool isExtColumn = !nppParams.getNppGUI()._fileSwitcherWithoutExtColumn;
bool isPathColumn = !nppParams.getNppGUI()._fileSwitcherWithoutPathColumn; bool isPathColumn = !nppParams.getNppGUI()._fileSwitcherWithoutPathColumn;
@ -111,7 +130,7 @@ void VerticalFileSwitcherListView::initList()
{ {
TaskLstFnStatus & fileNameStatus = taskListInfo._tlfsLst[i]; 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' }; TCHAR fn[MAX_PATH] = { '\0' };
wcscpy_s(fn, ::PathFindFileName(fileNameStatus._fn.c_str())); wcscpy_s(fn, ::PathFindFileName(fileNameStatus._fn.c_str()));
@ -121,13 +140,14 @@ void VerticalFileSwitcherListView::initList()
::PathRemoveExtension(fn); ::PathRemoveExtension(fn);
} }
LVITEM item{}; LVITEM item{};
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_GROUPID;
item.pszText = fn; item.pszText = fn;
item.iItem = static_cast<int32_t>(i); item.iItem = static_cast<int32_t>(i);
item.iSubItem = 0; item.iSubItem = 0;
item.iImage = fileNameStatus._status; item.iImage = fileNameStatus._status;
item.lParam = reinterpret_cast<LPARAM>(tl); item.lParam = reinterpret_cast<LPARAM>(tl);
item.iGroupId = (fileNameStatus._iView == MAIN_VIEW) ? _groupID : _group2ID;
ListView_InsertItem(_hSelf, &item); ListView_InsertItem(_hSelf, &item);
int colIndex = 0; int colIndex = 0;
if (isExtColumn) 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 generic_string VerticalFileSwitcherListView::getFullFilePath(size_t i) const
{ {
size_t nbItem = ListView_GetItemCount(_hSelf); size_t nbItem = ListView_GetItemCount(_hSelf);
@ -270,7 +314,7 @@ int VerticalFileSwitcherListView::add(BufferID bufferID, int iView)
Buffer *buf = static_cast<Buffer *>(bufferID); Buffer *buf = static_cast<Buffer *>(bufferID);
const TCHAR *fileName = buf->getFileName(); const TCHAR *fileName = buf->getFileName();
NppGUI& nppGUI = NppParameters::getInstance().getNppGUI(); 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' }; TCHAR fn[MAX_PATH] = { '\0' };
wcscpy_s(fn, ::PathFindFileName(fileName)); wcscpy_s(fn, ::PathFindFileName(fileName));
@ -281,13 +325,14 @@ int VerticalFileSwitcherListView::add(BufferID bufferID, int iView)
::PathRemoveExtension(fn); ::PathRemoveExtension(fn);
} }
LVITEM item{}; LVITEM item{};
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_GROUPID;
item.pszText = fn; item.pszText = fn;
item.iItem = _currentIndex; item.iItem = _currentIndex;
item.iSubItem = 0; item.iSubItem = 0;
item.iImage = buf->isMonitoringOn()?3:(buf->isReadOnly()?2:(buf->isDirty()?1:0)); item.iImage = buf->isMonitoringOn()?3:(buf->isReadOnly()?2:(buf->isDirty()?1:0));
item.lParam = reinterpret_cast<LPARAM>(tl); item.lParam = reinterpret_cast<LPARAM>(tl);
item.iGroupId = (iView == MAIN_VIEW) ? _groupID : _group2ID;
ListView_InsertItem(_hSelf, &item); ListView_InsertItem(_hSelf, &item);
int colIndex = 0; int colIndex = 0;
if (isExtColumn) 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_CLMNNAME "ColumnName"
#define FS_CLMNEXT "ColumnExt" #define FS_CLMNEXT "ColumnExt"
#define FS_CLMNPATH "ColumnPath" #define FS_CLMNPATH "ColumnPath"
#define FS_LVGROUPS "ListGroups"
struct SwitcherFileInfo { struct SwitcherFileInfo {
BufferID _bufID = 0; BufferID _bufID = 0;
@ -58,6 +59,7 @@ public:
void activateItem(BufferID bufferID, int iView); void activateItem(BufferID bufferID, int iView);
void setItemIconStatus(BufferID bufferID); void setItemIconStatus(BufferID bufferID);
generic_string getFullFilePath(size_t i) const; generic_string getFullFilePath(size_t i) const;
void setItemColor(BufferID bufferID);
void insertColumn(const TCHAR *name, int width, int index); void insertColumn(const TCHAR *name, int width, int index);
void resizeColumns(int totalWidth); void resizeColumns(int totalWidth);
@ -90,6 +92,9 @@ protected:
int _currentIndex = 0; int _currentIndex = 0;
static const int _groupID = 1;
static const int _group2ID = 2;
int find(BufferID bufferID, int iView) const; int find(BufferID bufferID, int iView) const;
int add(BufferID bufferID, int iView); int add(BufferID bufferID, int iView);
void remove(int index); void remove(int index);