diff --git a/gitfourchette/filelists/filelist.py b/gitfourchette/filelists/filelist.py index 9c4f2e71..227a2e1a 100644 --- a/gitfourchette/filelists/filelist.py +++ b/gitfourchette/filelists/filelist.py @@ -75,43 +75,68 @@ def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIn text = painter.fontMetrics().elidedText(fullText, option.textElideMode, textRect.width()) # Split path into directory and filename for better readability - dirPortion = None - filePortion = None - - if '/' in fullText: - slashesInFull = fullText.count('/') - slashesInElided = text.count('/') - - if slashesInFull > slashesInElided: - # A slash was elided - gray everything up to the ellipsis - ellipsisPos = text.find('\u2026') - dirPortion = text[:ellipsisPos + 1] - filePortion = text[ellipsisPos + 1:] - elif slashesInElided > 0: - # No slash elided - gray up to the last slash - lastSlash = text.rfind('/') - dirPortion = text[:lastSlash + 1] - filePortion = text[lastSlash + 1:] - - if dirPortion is not None: - textColor = QPalette.ColorRole.WindowText if not isSelected else QPalette.ColorRole.HighlightedText - dirColor = QPalette.ColorRole.PlaceholderText if not isSelected else textColor - - # Draw directory with muted color - mutedColor = option.palette.color(colorGroup, dirColor) - if isSelected: - mutedColor.setAlphaF(.7) - painter.setPen(mutedColor) - painter.drawText(textRect, option.displayAlignment, dirPortion) - - # Draw filename with normal color - painter.setPen(option.palette.color(colorGroup, textColor)) - dirWidth = painter.fontMetrics().horizontalAdvance(dirPortion) - fileRect = QRect(textRect) - fileRect.setLeft(textRect.left() + dirWidth) - painter.drawText(fileRect, option.displayAlignment, filePortion) + firstPortion = None + secondPortion = None + firstColor = QPalette.ColorRole.PlaceholderText + secondColor = QPalette.ColorRole.WindowText + + # Determine split based on style + isFileNameFirst = settings.prefs.pathDisplayStyle == PathDisplayStyle.FileNameFirst + + if isFileNameFirst: + try: + firstPortion, secondPortion = text.split('\0') + except ValueError: + firstPortion, secondPortion = text, "" + + firstColor = QPalette.ColorRole.WindowText + secondColor = QPalette.ColorRole.PlaceholderText + else: - painter.drawText(textRect, option.displayAlignment, text) + if '/' in fullText: + slashesInFull = fullText.count('/') + slashesInElided = text.count('/') + + if slashesInFull > slashesInElided: + # A slash was elided - gray everything up to the ellipsis + ellipsisPos = text.find('\u2026') + firstPortion = text[:ellipsisPos + 1] + secondPortion = text[ellipsisPos + 1:] + elif slashesInElided > 0: + # No slash elided - gray up to the last slash + lastSlash = text.rfind('/') + firstPortion = text[:lastSlash + 1] + secondPortion = text[lastSlash + 1:] + + if firstPortion is None: + firstPortion = "" + secondPortion = text + + firstColor = QPalette.ColorRole.PlaceholderText + secondColor = QPalette.ColorRole.WindowText + + # Draw the parts + if firstPortion: + fg1 = option.palette.color(colorGroup, firstColor if not isSelected else QPalette.ColorRole.HighlightedText) + if firstColor == QPalette.ColorRole.PlaceholderText and isSelected: + fg1 = QColor(option.palette.color(colorGroup, QPalette.ColorRole.HighlightedText)) + fg1.setAlphaF(0.7) + + painter.setPen(fg1) + painter.drawText(textRect, option.displayAlignment, firstPortion) + + # Prepare rect for second part + part1Width = painter.fontMetrics().horizontalAdvance(firstPortion) + textRect.setLeft(textRect.left() + part1Width) + + if secondPortion: + fg2 = option.palette.color(colorGroup, secondColor if not isSelected else QPalette.ColorRole.HighlightedText) + if secondColor == QPalette.ColorRole.PlaceholderText and isSelected: + fg2 = QColor(option.palette.color(colorGroup, QPalette.ColorRole.HighlightedText)) + fg2.setAlphaF(0.7) + + painter.setPen(fg2) + painter.drawText(textRect, option.displayAlignment, secondPortion) # Highlight search term if searchTerm and searchTerm in fullText.lower(): @@ -122,8 +147,11 @@ def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIn else: needleLen = len(searchTerm) + # Use original textRect (before we advanced it for the second part) + textRect.setLeft(textRect.left() - part1Width if firstPortion else 0) SearchBar.highlightNeedle(painter, textRect, text, needlePos, needleLen) + painter.restore() @@ -195,6 +223,8 @@ def __init__(self, repoModel: RepoModel, parent: QWidget, navContext: NavContext def refreshPrefs(self): self.setVerticalScrollMode(settings.prefs.listViewScrollMode) + nameFirst = settings.prefs.pathDisplayStyle == PathDisplayStyle.FileNameFirst + self.setTextElideMode(Qt.TextElideMode.ElideRight if nameFirst else Qt.TextElideMode.ElideMiddle) @property def repo(self) -> Repo: diff --git a/gitfourchette/toolbox/pathutils.py b/gitfourchette/toolbox/pathutils.py index 12b0d1d4..e06f268c 100644 --- a/gitfourchette/toolbox/pathutils.py +++ b/gitfourchette/toolbox/pathutils.py @@ -14,6 +14,7 @@ class PathDisplayStyle(enum.IntEnum): FullPaths = 1 AbbreviateDirs = 2 FileNameOnly = 3 + FileNameFirst = 4 def compactPath(path: str) -> str: @@ -33,6 +34,11 @@ def abbreviatePath(path: str, style: PathDisplayStyle = PathDisplayStyle.FullPat else: splitLong[i] = splitLong[i][0] return '/'.join(splitLong) + elif style == PathDisplayStyle.FileNameFirst: + split = path.rsplit('/', 1) + if len(split) == 1: + return path + return split[-1] + ' \0' + split[0] elif style == PathDisplayStyle.FileNameOnly: return path.rsplit('/', 1)[-1] else: diff --git a/gitfourchette/trtables.py b/gitfourchette/trtables.py index fc6eb016..c0cbe0c7 100644 --- a/gitfourchette/trtables.py +++ b/gitfourchette/trtables.py @@ -195,6 +195,7 @@ def _init_enums(): PathDisplayStyle.FullPaths : _("Full paths"), PathDisplayStyle.AbbreviateDirs : _("Abbreviate directories"), PathDisplayStyle.FileNameOnly : _("Show filename only"), + PathDisplayStyle.FileNameFirst : _("Filename first"), }, AuthorDisplayStyle: { diff --git a/test/test_filelist.py b/test/test_filelist.py index 79bd6e2d..16883c9a 100644 --- a/test/test_filelist.py +++ b/test/test_filelist.py @@ -498,6 +498,9 @@ def testFileListChangePathDisplayStyle(tempDir, mainWindow): triggerContextMenuAction(rw.committedFiles.viewport(), "path display style/full") assert ["c/c2-2.txt"] == qlvGetRowData(rw.committedFiles) + triggerContextMenuAction(rw.committedFiles.viewport(), "path display style/name first") + assert ["c2-2.txt \0c"] == qlvGetRowData(rw.committedFiles) + def testFileListShowInFolder(tempDir, mainWindow): wd = unpackRepo(tempDir)