[PATCH 1 of 8 DarkThemeSeries 3] status: preserve file status colors on selection (working copy)

2 views
Skip to first unread message

Peter Demcak

unread,
Mar 8, 2026, 1:19:44 AM (2 days ago) Mar 8
to thg...@googlegroups.com
# HG changeset patch
# User Peter Demcak <majs...@gmail.com>
# Date 1772737300 -3600
# Thu Mar 05 20:01:40 2026 +0100
# Node ID 3d13661e5918e157be75a4cc81b822c9ac520292
# Parent 851dc4bb18fcfb43622489de1bdfa8c4b3e75939
status: preserve file status colors on selection (working copy)

Prevents Qt selection highlighting from overriding
per-file status colors in the working copy view.

diff -r 851dc4bb18fc -r 3d13661e5918 tortoisehg/hgqt/status.py
--- a/tortoisehg/hgqt/status.py Thu Mar 05 20:01:16 2026 +0100
+++ b/tortoisehg/hgqt/status.py Thu Mar 05 20:01:40 2026 +0100
@@ -28,6 +28,7 @@
from .qtgui import (
QAbstractItemView,
QAction,
+ QBrush,
QCheckBox,
QColor,
QDialog,
@@ -40,6 +41,8 @@
QShortcut,
QSizePolicy,
QSplitter,
+ QStyleOptionViewItem,
+ QStyledItemDelegate,
QToolBar,
QToolButton,
QTreeView,
@@ -75,6 +78,9 @@
Dict,
)

+from .qtcore import Qt, QTimer
+from .theme import THEME
+
# This widget can be used as the basis of the commit tool or any other
# working copy browser.

@@ -199,6 +205,10 @@
self.runCustomCommandRequested)
self.addActions(self._fileactions.actions())
tv = WctxFileTree(self)
+
+ if THEME.enabled:
+ tv.setItemDelegate(WctxPreserveStatusColorDelegate(tv))
+
vbox.addLayout(hbox)
vbox.addWidget(tv)
split.addWidget(frame)
@@ -776,6 +786,25 @@
except error.Abort as e:
self.showMessage.emit(hglib.exception_str(e, show_hint=True))

+class WctxPreserveStatusColorDelegate(QStyledItemDelegate):
+ def paint(self, painter, option, index):
+ opt = QStyleOptionViewItem(option)
+ self.initStyleOption(opt, index)
+
+ if qtlib.stateValue(opt.state) & qtlib.QtStateFlag.State_Selected:
+ fg = index.data(qtlib.QtItemDataRole.ForegroundRole)
+ if isinstance(fg, QBrush):
+ brush = fg
+ elif fg is not None:
+ brush = QBrush(fg)
+ else:
+ brush = opt.palette.brush(qtlib.QtPaletteRole.Text)
+
+ # critical: keyboard selection path uses HighlightedText
+ opt.palette.setBrush(qtlib.QtPaletteRole.HighlightedText, brush)
+ opt.palette.setBrush(qtlib.QtPaletteRole.Text, brush)
+
+ super().paint(painter, opt, index)

class WctxFileTree(QTreeView):

@@ -785,6 +814,28 @@
super().scrollTo(index, hint)
self.horizontalScrollBar().setValue(orighoriz)

+
+ def drawRow(self, painter, option, index):
+ if qtlib.stateValue(option.state) & qtlib.QtStateFlag.State_Selected:
+ opt = QStyleOptionViewItem(option)
+
+ # get per-item foreground color (status color)
+ fg = index.data(qtlib.QtItemDataRole.ForegroundRole)
+ if isinstance(fg, QBrush):
+ brush = fg
+ elif fg is not None:
+ brush = QBrush(fg)
+ else:
+ brush = opt.palette.brush(qtlib.QtPaletteRole.Text)
+
+ # force Qt to use status color even for keyboard selection
+ opt.palette.setBrush(qtlib.QtPaletteRole.HighlightedText, brush)
+ opt.palette.setBrush(qtlib.QtPaletteRole.Text, brush)
+
+ super().drawRow(painter, opt, index)
+ return
+
+ super().drawRow(painter, option, index)

class WctxModel(QAbstractTableModel):
checkCountChanged = pyqtSignal()

Peter Demcak

unread,
Mar 8, 2026, 1:19:45 AM (2 days ago) Mar 8
to thg...@googlegroups.com
# HG changeset patch
# User Peter Demcak <majs...@gmail.com>
# Date 1772737327 -3600
# Thu Mar 05 20:02:07 2026 +0100
# Node ID 1f8b7230d16f6d8e2d755d1dacc2406a3e00b6f3
# Parent 3d13661e5918e157be75a4cc81b822c9ac520292
merge/revpanel: use theme colors for warning messages

Use THEME warning colors for “Creates new head!” and “Reopens closed branch head!”
in merge.py and revpanel.py. Keep red bold text as fallback when theme is disabled.

diff -r 3d13661e5918 -r 1f8b7230d16f tortoisehg/hgqt/merge.py
--- a/tortoisehg/hgqt/merge.py Thu Mar 05 20:01:40 2026 +0100
+++ b/tortoisehg/hgqt/merge.py Thu Mar 05 20:02:07 2026 +0100
@@ -49,6 +49,8 @@
wctxcleaner,
)



+from .theme import THEME
+

MARGINS = (8, 0, 0, 0)

class MergeDialog(QWizard):
@@ -188,7 +190,13 @@
def markup_func(widget, item, value):
if item == 'createsnewhead' and value is True:
text = _('Creates new head!')
- return qtlib.markup(text, fg='red', weight='bold')
+ if THEME.enabled:
+ return qtlib.markup(text,
+ fg=THEME.warning_text.name(),
+ bg=THEME.warning_background.name(),
+ weight='bold')
+ else:
+ return qtlib.markup(text, fg='red', weight='bold')
raise csinfo.UnknownItem(item)
custom = csinfo.custom(markup=markup_func)
create = csinfo.factory(repo, custom, style, withupdate=True)
diff -r 3d13661e5918 -r 1f8b7230d16f tortoisehg/hgqt/revpanel.py
--- a/tortoisehg/hgqt/revpanel.py Thu Mar 05 20:01:40 2026 +0100
+++ b/tortoisehg/hgqt/revpanel.py Thu Mar 05 20:02:07 2026 +0100
@@ -20,6 +20,8 @@
qtlib,
)



+from .theme import THEME
+

def label_func(widget, item, ctx):
if item == 'cset':
if isinstance(ctx.rev(), str):
@@ -207,7 +209,13 @@
if item == 'createsnewhead':
if value is True:
text = _('Creates new head!')
- return qtlib.markup(text, fg='red', weight='bold')
+ if THEME.enabled:
+ return qtlib.markup(text,
+ fg=THEME.warning_text.name(),
+ bg=THEME.warning_background.name(),
+ weight='bold')
+ else:
+ return qtlib.markup(text, fg='red', weight='bold')
raise csinfo.UnknownItem(item)
elif item == 'createsorphans':
if value is True:
@@ -217,7 +225,13 @@
elif item == 'reopensbranchhead':
if value is True:
text = _('Reopens closed branch head!')
- return qtlib.markup(text, fg='red', weight='bold')
+ if THEME.enabled:
+ return qtlib.markup(text,
+ fg=THEME.warning_text.name(),
+ bg=THEME.warning_background.name(),
+ weight='bold')
+ else:
+ return qtlib.markup(text, fg='red', weight='bold')
raise csinfo.UnknownItem(item)
for cset in value:
if hglib.isbasestring(cset):

Peter Demcak

unread,
Mar 8, 2026, 1:19:46 AM (2 days ago) Mar 8
to thg...@googlegroups.com
# HG changeset patch
# User Peter Demcak <majs...@gmail.com>
# Date 1772737346 -3600
# Thu Mar 05 20:02:26 2026 +0100
# Node ID 9f2a9465fac731919668042ac8c55434cae9f4e7
# Parent 1f8b7230d16f6d8e2d755d1dacc2406a3e00b6f3
filedata: use theme-aware color for exec mode set/unset labels

Replace hardcoded red HTML font tags with theme-based
span colors for “exec mode has been set/unset” messages when theme support
is enabled.

diff -r 1f8b7230d16f -r 9f2a9465fac7 tortoisehg/hgqt/filedata.py
--- a/tortoisehg/hgqt/filedata.py Thu Mar 05 20:02:07 2026 +0100
+++ b/tortoisehg/hgqt/filedata.py Thu Mar 05 20:02:26 2026 +0100
@@ -53,6 +53,7 @@
ThgContext,


)

+from .theme import THEME

forcedisplaymsg = _('Display the file anyway')

@@ -440,10 +441,16 @@
return
for pctx in ctx.parents():
if b'x' in fctx.flags() and b'x' not in pctx.flags(wfile):
- self.elabel = _("exec mode has been "
+ if THEME.enabled:
+ self.elabel = _("exec mode has been <span style='color:%s'>set</span>") % THEME.ui_info.name()
+ else:
+ self.elabel = _("exec mode has been "
"<font color='red'>set</font>")
elif b'x' not in fctx.flags() and b'x' in pctx.flags(wfile):
- self.elabel = _("exec mode has been "
+ if THEME.enabled:
+ self.elabel = _("exec mode has been <span style='color:%s'>unset</span>") % THEME.ui_info.name()
+ else:
+ self.elabel = _("exec mode has been "
"<font color='red'>unset</font>")

if status == 'A':
@@ -584,10 +591,16 @@
return

if flags == b'x':
- self.elabel = _("exec mode has been "
+ if THEME.enabled:
+ self.elabel = _("exec mode has been <span style='color:%s'>set</span>") % THEME.ui_info.name()
+ else:
+ self.elabel = _("exec mode has been "
"<font color='red'>set</font>")
elif flags == b'-':
- self.elabel = _("exec mode has been "
+ if THEME.enabled:
+ self.elabel = _("exec mode has been <span style='color:%s'>unset</span>") % THEME.ui_info.name()
+ else:
+ self.elabel = _("exec mode has been "
"<font color='red'>unset</font>")
elif flags == b'l':
self.flabel += _(' <i>(is a symlink)</i>')

Peter Demcak

unread,
Mar 8, 2026, 1:19:48 AM (2 days ago) Mar 8
to thg...@googlegroups.com
# HG changeset patch
# User Peter Demcak <majs...@gmail.com>
# Date 1772929603 -3600
# Sun Mar 08 01:26:43 2026 +0100
# Node ID 0ffb2fd7d9b1cafd42f220291f1e7cac3f3c3fd1
# Parent 9f2a9465fac731919668042ac8c55434cae9f4e7
repofilter: use theme colors for revset type label

diff -r 9f2a9465fac7 -r 0ffb2fd7d9b1 tortoisehg/hgqt/repofilter.py
--- a/tortoisehg/hgqt/repofilter.py Thu Mar 05 20:02:26 2026 +0100
+++ b/tortoisehg/hgqt/repofilter.py Sun Mar 08 01:26:43 2026 +0100
@@ -66,6 +66,8 @@
thgrepo,
)

+from .theme import THEME
+
_permanent_queries = ('head()', 'merge()',
'tagged()', 'bookmark()',
'file(".hgsubstate") or file(".hgsub")')
@@ -334,8 +336,21 @@
name += ' ' + _('(unsaved)')
label = self._revsettypelabel
label.setText(name)
- label.setStyleSheet('border: 1px solid %s; background-color: %s; '
- 'color: black;' % (bordercolor, bgcolor))
+
+ if THEME.enabled:
+ bordercolor = THEME.text_disabled.name()
+ textcolor = THEME.text.name()
+ if qtype == 'keyword':
+ bgcolor = THEME.background.name()
+ else:
+ bgcolor = THEME.backgroundLighter.name()
+ else:
+ textcolor = 'black'
+
+ label.setStyleSheet('border: 1px solid %s; background-color: %s;'
+ 'color: %s;' % (bordercolor, bgcolor, textcolor)
+ )
+
label.show()
self._updateQueryTypeGeometry()


Peter Demcak

unread,
Mar 8, 2026, 1:19:49 AM (2 days ago) Mar 8
to thg...@googlegroups.com
# HG changeset patch
# User Peter Demcak <majs...@gmail.com>
# Date 1772929674 -3600
# Sun Mar 08 01:27:54 2026 +0100
# Node ID e1c3b29220a26a9a41c6747af80ec813a3017fa5
# Parent 0ffb2fd7d9b1cafd42f220291f1e7cac3f3c3fd1
qscilib: add dark theme styling for hgrc/mercurial.ini editors

Apply THEME colors to editor text, margins, folding markers, lexer styles,
caret, current line, and selection.

diff -r 0ffb2fd7d9b1 -r e1c3b29220a2 tortoisehg/hgqt/qscilib.py
--- a/tortoisehg/hgqt/qscilib.py Sun Mar 08 01:26:43 2026 +0100
+++ b/tortoisehg/hgqt/qscilib.py Sun Mar 08 01:27:54 2026 +0100
@@ -34,6 +34,7 @@
QAction,
QApplication,
QCheckBox,
+ QColor,
QDialog,
QDialogButtonBox,
QInputMethodEvent,
@@ -48,6 +49,7 @@
from ..util import hglib
from ..util.i18n import _
from . import qtlib
+from .theme import THEME

# indicator for highlighting preedit text of input method
_IM_PREEDIT_INDIC_ID = QsciScintilla.INDIC_MAX
@@ -841,6 +843,50 @@
editor.setFolding(QsciScintilla.FoldStyle.BoxedTreeFoldStyle)
dialog.layout().addWidget(editor)

+ if THEME.enabled:
+
+ # Text (editor content)
+ editor.SendScintilla(QsciScintilla.SCI_STYLESETBACK, QsciScintilla.STYLE_DEFAULT, THEME.background)
+ editor.SendScintilla(QsciScintilla.SCI_STYLESETFORE, QsciScintilla.STYLE_DEFAULT, THEME.diff_text)
+
+ # Margins (line numbers, symbol margins)
+ editor.setMarginsBackgroundColor(THEME.background)
+ editor.setMarginsForegroundColor(THEME.diff_text)
+
+ # Folding marker symbols (PlainFoldStyle)
+ editor.setMarkerBackgroundColor(THEME.background, QsciScintilla.SC_MARKNUM_FOLDER)
+ editor.setMarkerForegroundColor(THEME.diff_text, QsciScintilla.SC_MARKNUM_FOLDER)
+
+ editor.setMarkerBackgroundColor(THEME.background, QsciScintilla.SC_MARKNUM_FOLDEROPEN)
+ editor.setMarkerForegroundColor(THEME.diff_text, QsciScintilla.SC_MARKNUM_FOLDEROPEN)
+
+ # Lexer styles (apply dark background to all, then override sections)
+ for style in range(128):
+ lexer.setPaper(THEME.background, style)
+ lexer.setColor(THEME.diff_text, style)
+
+ lexer.setColor(THEME.diff_start, QsciLexerProperties.Section)
+
+ # Folding margin (visual container)
+ editor.setMarginType(2, QsciScintilla.MarginType.SymbolMargin)
+ editor.setMarginWidth(2, 12)
+ editor.setMarginBackgroundColor(2, THEME.background)
+ editor.setFoldMarginColors(THEME.background, THEME.config_scrollbar)
+
+ # Caret (cursor)
+ editor.setCaretForegroundColor(THEME.caret_foreground)
+
+ # Caret line (current line highlight)
+ editor.setCaretLineVisible(True)
+ editor.setCaretLineBackgroundColor(THEME.backgroundLighter)
+
+ # Selection
+ editor.setSelectionBackgroundColor(THEME.selection_background)
+ editor.setSelectionForegroundColor(THEME.selection_text)
+
+ # Folding style (avoid white checkboxes)
+ editor.setFolding(QsciScintilla.FoldStyle.PlainFoldStyle)
+
searchbar = SearchToolBar(dialog)
searchbar.searchRequested.connect(editor.find)
searchbar.conditionChanged.connect(editor.highlightText)

Peter Demcak

unread,
Mar 8, 2026, 1:19:49 AM (2 days ago) Mar 8
to thg...@googlegroups.com
# HG changeset patch
# User Peter Demcak <majs...@gmail.com>
# Date 1772929780 -3600
# Sun Mar 08 01:29:40 2026 +0100
# Node ID 2ebf0382799fb93d04ea95c6f88e369bd98dd09a
# Parent e1c3b29220a26a9a41c6747af80ec813a3017fa5
repoview: align header text; apply row selection workaround for Windows 11/PyQt6

- align header text to left/vertical center in themed mode
- add SelectionWorkaroundDelegate that fills selected row rect with
THEME.selection_background before default painting
- install the delegate at view level when THEME is enabled so the fix applies
consistently across columns
- make GraphDelegate and LabeledDelegate inherit from the workaround delegate
so custom painting paths keep the same selection behavior
- keep legacy/default painting path when theme support is disabled
- tested on Windows 11 (target fix), Windows 10, and Ubuntu 22.04 with both Qt5
and Qt6

diff -r e1c3b29220a2 -r 2ebf0382799f tortoisehg/hgqt/repoview.py
--- a/tortoisehg/hgqt/repoview.py Sun Mar 08 01:27:54 2026 +0100
+++ b/tortoisehg/hgqt/repoview.py Sun Mar 08 01:29:40 2026 +0100
@@ -73,6 +73,7 @@
qtlib,
repomodel,
)
+from .theme import THEME

class HgRepoView(QTableView):

@@ -107,6 +108,13 @@
header.sectionMoved.connect(self._saveColumnSettings)

self.createActions()
+
+ if THEME.enabled:
+ header.setDefaultAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
+
+ # Set delegate for all columns to apply selection background workaround
+ self.setItemDelegate(SelectionWorkaroundDelegate(self))
+
self.setItemDelegateForColumn(repomodel.GraphColumn,
GraphDelegate(self))
self.setItemDelegateForColumn(repomodel.DescColumn,
@@ -534,7 +542,17 @@
return colors[edge.color % len(colors)]


-class GraphDelegate(QStyledItemDelegate):
+class SelectionWorkaroundDelegate(QStyledItemDelegate):
+ """Delegate that applies Windows 11 PyQt6 selection background workaround"""
+
+ def paint(self, painter, option, index):
+ if THEME.enabled:
+ if qtlib.stateValue(option.state) & qtlib.QtStateFlag.State_Selected:
+ painter.fillRect(option.rect, THEME.selection_background)
+ super().paint(painter, option, index)
+
+
+class GraphDelegate(SelectionWorkaroundDelegate):

def __init__(self, parent=None):
super().__init__(parent)
@@ -552,7 +570,11 @@
return 0.4 * self._rowheight

def paint(self, painter, option, index):
- QStyledItemDelegate.paint(self, painter, option, index)
+ if THEME.enabled:
+ super().paint(painter, option, index)
+ else:
+ QStyledItemDelegate.paint(self, painter, option, index)
+
# update to the actual height that should be the same for all rows
self._rowheight = option.rect.height()
visibleend = self._colcount(option.rect.width())
@@ -775,7 +797,7 @@
x += lw + self._margin


-class LabeledDelegate(QStyledItemDelegate):
+class LabeledDelegate(SelectionWorkaroundDelegate):
"""Render text labels in place of icon/pixmap decoration"""

def __init__(self, parent=None, margin=2):

Peter Demcak

unread,
Mar 8, 2026, 1:19:51 AM (2 days ago) Mar 8
to thg...@googlegroups.com
# HG changeset patch
# User Peter Demcak <majs...@gmail.com>
# Date 1772930193 -3600
# Sun Mar 08 01:36:33 2026 +0100
# Node ID ec21747b1e33b0928a25f9be8809261360b2053a
# Parent 2ebf0382799fb93d04ea95c6f88e369bd98dd09a
filedialogs, rejects: apply theme when merging chunk conflicts

- Add diff_removed_bg and reject_baseline_bg colors to the dark theme.
- Add THEME colors to filedialogs.py for margins,
caret, selection, scrollbars and diff colormap.
- Add THEME colors to rejects.py margins, folding, caret, selection,
baseline marker, and RejectBrowser, +/- marker symbols and line backgrounds.

diff -r 2ebf0382799f -r ec21747b1e33 tortoisehg/hgqt/filedialogs.py
--- a/tortoisehg/hgqt/filedialogs.py Sun Mar 08 01:29:40 2026 +0100
+++ b/tortoisehg/hgqt/filedialogs.py Sun Mar 08 01:36:33 2026 +0100
@@ -70,6 +70,7 @@
revpanel,
)
from .qscilib import Scintilla
+from .theme import THEME

if typing.TYPE_CHECKING:
from typing import (
@@ -86,11 +87,18 @@
_MARKERPLUSUNDERLINE = 29
_MARKERMINUSUNDERLINE = 28

-_colormap = {
- '+': QColor(0xA0, 0xFF, 0xB0),
- '-': QColor(0xFF, 0xA0, 0xA0),
- 'x': QColor(0xA0, 0xA0, 0xFF)
- }
+if THEME.enabled:
+ _colormap = {
+ '+': THEME.diff_added_bg,
+ '-': THEME.diff_removed_bg,
+ 'x': THEME.diff_added2_bg,
+ }
+else:
+ _colormap = {
+ '+': QColor(0xA0, 0xFF, 0xB0),
+ '-': QColor(0xFF, 0xA0, 0xA0),
+ 'x': QColor(0xA0, 0xA0, 0xFF),
+ }

def _setupFileMenu(menu, fileactions):
for name in ['visualDiff', 'visualDiffToLocal', None,
@@ -558,6 +566,20 @@
self.markerminusunderline = sci.markerDefine(QsciScintilla.MarkerSymbol.Invisible,
_MARKERMINUSUNDERLINE)

+ if THEME.enabled:
+ # Margin colors (line numbers area)
+ sci.setMarginsBackgroundColor(THEME.background)
+ sci.setMarginsForegroundColor(THEME.diff_text)
+
+ # Caret
+ sci.setCaretForegroundColor(THEME.caret_foreground)
+ sci.setCaretLineVisible(True)
+ sci.setCaretLineBackgroundColor(THEME.backgroundLighter)
+
+ # Selection
+ sci.setSelectionBackgroundColor(THEME.selection_background)
+ sci.setSelectionForegroundColor(THEME.selection_text)
+
self.viewers[side] = sci
blk = blockmatcher.BlockList(self.frame)
blk.linkScrollBar(sci.verticalScrollBar())
diff -r 2ebf0382799f -r ec21747b1e33 tortoisehg/hgqt/rejects.py
--- a/tortoisehg/hgqt/rejects.py Sun Mar 08 01:29:40 2026 +0100
+++ b/tortoisehg/hgqt/rejects.py Sun Mar 08 01:36:33 2026 +0100
@@ -42,6 +42,8 @@
qtlib,
)

+from .theme import THEME
+
qsci = Qsci.QsciScintilla

class RejectsDialog(QDialog):
@@ -61,7 +63,10 @@
editor.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
editor.customContextMenuRequested.connect(self._onMenuRequested)
self.baseLineColor = editor.markerDefine(qsci.MarkerSymbol.Background, -1)
- editor.setMarkerBackgroundColor(QColor('lightblue'), self.baseLineColor)
+ if THEME.enabled:
+ editor.setMarkerBackgroundColor(THEME.reject_baseline_bg, self.baseLineColor)
+ else:
+ editor.setMarkerBackgroundColor(QColor('lightblue'), self.baseLineColor)
layout.addWidget(editor, 3)

searchbar = qscilib.SearchToolBar(self)
@@ -135,6 +140,32 @@
editor.setMarginLineNumbers(1, True)
editor.setMarginWidth(1, str(editor.lines())+'X')

+ if THEME.enabled:
+ # Margin colors (line numbers area)
+ editor.setMarginsBackgroundColor(THEME.background)
+ editor.setMarginsForegroundColor(THEME.diff_text)
+
+ # Folding markers
+ editor.setMarkerBackgroundColor(THEME.background, qsci.SC_MARKNUM_FOLDER)
+ editor.setMarkerForegroundColor(THEME.diff_text, qsci.SC_MARKNUM_FOLDER)
+ editor.setMarkerBackgroundColor(THEME.background, qsci.SC_MARKNUM_FOLDEROPEN)
+ editor.setMarkerForegroundColor(THEME.diff_text, qsci.SC_MARKNUM_FOLDEROPEN)
+
+ # Folding margin background
+ editor.setFoldMarginColors(THEME.background, THEME.config_scrollbar)
+
+ # Folding style (avoid white checkboxes)
+ editor.setFolding(qsci.FoldStyle.PlainFoldStyle)
+
+ # Caret
+ editor.setCaretForegroundColor(THEME.caret_foreground)
+ editor.setCaretLineVisible(True)
+ editor.setCaretLineBackgroundColor(THEME.backgroundLighter)
+
+ # Selection
+ editor.setSelectionBackgroundColor(THEME.selection_background)
+ editor.setSelectionForegroundColor(THEME.selection_text)
+
buf = util.bytesio()
try:
buf.write(b'diff -r aaaaaaaaaaaa -r bbbbbbbbbbb %s\n' % path)
@@ -288,8 +319,17 @@
self.removedMark = self.markerDefine(qsci.MarkerSymbol.Minus, -1)
self.addedColor = self.markerDefine(qsci.MarkerSymbol.Background, -1)
self.removedColor = self.markerDefine(qsci.MarkerSymbol.Background, -1)
- self.setMarkerBackgroundColor(QColor('lightgreen'), self.addedColor)
- self.setMarkerBackgroundColor(QColor('cyan'), self.removedColor)
+ if THEME.enabled:
+ self.setMarkerBackgroundColor(THEME.diff_added_bg, self.addedColor)
+ self.setMarkerBackgroundColor(THEME.diff_removed_bg, self.removedColor)
+ # Plus/Minus marker symbol colors
+ self.setMarkerForegroundColor(THEME.diff_added, self.addedMark)
+ self.setMarkerBackgroundColor(THEME.background, self.addedMark)
+ self.setMarkerForegroundColor(THEME.diff_removed, self.removedMark)
+ self.setMarkerBackgroundColor(THEME.background, self.removedMark)
+ else:
+ self.setMarkerBackgroundColor(QColor('lightgreen'), self.addedColor)
+ self.setMarkerBackgroundColor(QColor('cyan'), self.removedColor)
mask = (1 << self.addedMark) | (1 << self.removedMark) | \
(1 << self.addedColor) | (1 << self.removedColor)
self.setMarginMarkerMask(1, mask)
@@ -297,6 +337,14 @@
self.setFont(qtlib.getfont('fontdiff').font())
self.setLexer(lexer)

+ if THEME.enabled:
+ # Margin colors
+ self.setMarginsBackgroundColor(THEME.background)
+ self.setMarginsForegroundColor(THEME.diff_text)
+
+ # Caret
+ self.setCaretForegroundColor(THEME.caret_foreground)
+
def showChunk(self, lines):
utext = []
added = []
diff -r 2ebf0382799f -r ec21747b1e33 tortoisehg/hgqt/theme.py
--- a/tortoisehg/hgqt/theme.py Sun Mar 08 01:29:40 2026 +0100
+++ b/tortoisehg/hgqt/theme.py Sun Mar 08 01:36:33 2026 +0100
@@ -61,7 +61,9 @@
'diff_selected': QColor("#141414"),
'diff_excluded': QColor("#26282E"),
'diff_added_bg': QColor("#1C3A23"),
+ 'diff_removed_bg': QColor("#3A1C23"),
'diff_added2_bg': QColor("#24244A"),
+ 'reject_baseline_bg': QColor("#1C2A3A"),
'file_modified': QColor("#548CC4"),
'file_resolved': QColor("#30AF50"),
'file_added': QColor('#6FCF97'),

Peter Demcak

unread,
Mar 8, 2026, 1:19:52 AM (2 days ago) Mar 8
to thg...@googlegroups.com
# HG changeset patch
# User Peter Demcak <majs...@gmail.com>
# Date 1772930933 -3600
# Sun Mar 08 01:48:53 2026 +0100
# Node ID 5a7d494b3fb1862dcc148b9ffceba4101c92744f
# Parent ec21747b1e33b0928a25f9be8809261360b2053a
qtlib: replace default scrollbars for dark theme to fix Qt stylesheet deadzone

Add CustomScrollBar and applyCustomScrollBars() to work around a Qt stylesheet
issue where oversized scrollbar handles can create a dead zone near the end,
preventing scrolling to the bottom.
The issue occurs when any Scrollbar::handle style parameter is set.

The bug is most visible when the content is only slightly taller than
the viewport (for example, ~15 lines of text out of ~16 lines visible):
the scrollbar handle nearly fills the track, creating a dead zone near
the bottom and preventing scrolling to the true end.

Also add bidirectional scrollbar sync for QsciScintilla widgets and reconnect
QAbstractItemView scrollbar signals to preserve lazy-loading behavior.

diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/bookmark.py
--- a/tortoisehg/hgqt/bookmark.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/bookmark.py Sun Mar 08 01:48:53 2026 +0100
@@ -48,6 +48,7 @@
cmdcore,
qtlib,
)
+from .theme import THEME

class BookmarkDialog(QDialog):

@@ -310,6 +311,8 @@
self._onOutgoingMenuRequested)
self.outgoingList.itemSelectionChanged.connect(self._updateActions)
outgoingLayout.addWidget(self.outgoingList)
+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(self.outgoingList)

self._outactions = []
a = QAction(_('&Push Bookmark'), self)
@@ -341,6 +344,8 @@
self._onIncomingMenuRequested)
self.incomingList.itemSelectionChanged.connect(self._updateActions)
incomingLayout.addWidget(self.incomingList)
+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(self.incomingList)

self._inactions = []
a = QAction(_('P&ull Bookmark'), self)
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/chunks.py
--- a/tortoisehg/hgqt/chunks.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/chunks.py Sun Mar 08 01:48:53 2026 +0100
@@ -631,6 +631,8 @@
self.sci.setMarginsBackgroundColor(THEME.backgroundLighter)
self.sci.setMarginsForegroundColor(THEME.control_text)

+ qtlib.applyCustomScrollBars(self.sci)
+
if THEME.enabled and sys.platform == 'win32':
# Draw custom checkboxes for Windows: the margin is 12px wide on this platform
# Not needed for Linux, as the margin is 16px wide
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/cmdui.py
--- a/tortoisehg/hgqt/cmdui.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/cmdui.py Sun Mar 08 01:48:53 2026 +0100
@@ -234,7 +234,8 @@

if THEME.enabled:
self._apply_dark_console_markers()
-
+ qtlib.applyCustomScrollBars(self)
+
qscilib.unbindConflictedKeys(self)

def _initfont(self):
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/docklog.py
--- a/tortoisehg/hgqt/docklog.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/docklog.py Sun Mar 08 01:48:53 2026 +0100
@@ -105,6 +105,9 @@
self.setMarkerBackgroundColor(QColor('#e8f3fe'), self._prompt_marker)


+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(self)
+
self.cursorPositionChanged.connect(self._updatePrompt)
# ensure not moving prompt line even if completion list get shorter,
# by allowing to scroll one page below the last line
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/filedialogs.py
--- a/tortoisehg/hgqt/filedialogs.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/filedialogs.py Sun Mar 08 01:48:53 2026 +0100
@@ -580,6 +580,8 @@
sci.setSelectionBackgroundColor(THEME.selection_background)
sci.setSelectionForegroundColor(THEME.selection_text)

+ qtlib.applyCustomScrollBars(sci)
+
self.viewers[side] = sci
blk = blockmatcher.BlockList(self.frame)
blk.linkScrollBar(sci.verticalScrollBar())
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/filelistview.py
--- a/tortoisehg/hgqt/filelistview.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/filelistview.py Sun Mar 08 01:48:53 2026 +0100
@@ -47,6 +47,7 @@
QWidget,
)

+from .theme import THEME

class HgFileListView(QTreeView):
"""Display files and statuses between two revisions or patch"""
@@ -66,6 +67,9 @@
self.setIconSize(qtlib.smallIconSize())
self.setUniformRowHeights(True)

+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(self)
+
def _model(self) -> manifestmodel.ManifestModel:
model = self.model()
assert isinstance(model, manifestmodel.ManifestModel)
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/fileview.py
--- a/tortoisehg/hgqt/fileview.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/fileview.py Sun Mar 08 01:48:53 2026 +0100
@@ -182,6 +182,8 @@
self.sci.setWhitespaceBackgroundColor(THEME.background)
self.sci.setWhitespaceForegroundColor(THEME.text_margin)

+ qtlib.applyCustomScrollBars(self.sci)
+
hbox.addWidget(self.blk)
hbox.addWidget(self.sci, 1)
hbox.addWidget(self.blksearch)
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/grep.py
--- a/tortoisehg/hgqt/grep.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/grep.py Sun Mar 08 01:48:53 2026 +0100
@@ -74,6 +74,7 @@
thgrepo,
visdiff,
)
+from .theme import THEME

# This widget can be embedded in any application that would like to
# provide search features
@@ -636,6 +637,9 @@
self.setModel(MatchModel(repoagent, self))
self.selectionModel().selectionChanged.connect(self.onSelectionChanged)

+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(self)
+
@property
def repo(self):
return self._repoagent.rawRepo()
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/guess.py
--- a/tortoisehg/hgqt/guess.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/guess.py Sun Mar 08 01:48:53 2026 +0100
@@ -59,6 +59,7 @@
htmlui,
qtlib,
)
+from .theme import THEME

# Techincal debt
# Try to cut down on the jitter when findRenames is pressed. May
@@ -115,6 +116,8 @@
self.unrevlist.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
self.unrevlist.doubleClicked.connect(self.onUnrevDoubleClicked)
utvbox.addWidget(self.unrevlist)
+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(self.unrevlist)

simhbox = QHBoxLayout()
utvbox.addLayout(simhbox)
@@ -165,6 +168,8 @@
matchvbox.addWidget(matchtv)
matchvbox.addLayout(buthbox)
self.matchtv, self.matchbtn = matchtv, matchbtn
+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(matchtv)
def matchselect(s, d):
count = len(matchtv.selectedIndexes())
if count:
@@ -189,6 +194,8 @@
difftb.document().setDefaultStyleSheet(qtlib.thgstylesheet)
diffvbox.addWidget(difftb)
self.difftb = difftb
+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(difftb)

self.stbar = cmdui.ThgStatusBar()
layout.addWidget(self.stbar)
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/hgignore.py
--- a/tortoisehg/hgqt/hgignore.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/hgignore.py Sun Mar 08 01:48:53 2026 +0100
@@ -66,6 +66,7 @@
qscilib,
qtlib,
)
+from .theme import THEME

if typing.TYPE_CHECKING:
from .thgrepo import RepoAgent
@@ -164,6 +165,9 @@
unknownlist = QListWidget()
uvbox.addWidget(unknownlist)
unknownlist.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(ignorelist)
+ qtlib.applyCustomScrollBars(unknownlist)
unknownlist.currentTextChanged.connect(self.setGlobFilter)
unknownlist.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
unknownlist.customContextMenuRequested.connect(self.menuRequest)
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/messageentry.py
--- a/tortoisehg/hgqt/messageentry.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/messageentry.py Sun Mar 08 01:48:53 2026 +0100
@@ -71,6 +71,8 @@

if THEME.enabled:

+ qtlib.applyCustomScrollBars(self)
+
# Base editor colors
self.setPaper(THEME.background)
self.setColor(THEME.text)
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/mq.py
--- a/tortoisehg/hgqt/mq.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/mq.py Sun Mar 08 01:48:53 2026 +0100
@@ -66,6 +66,7 @@
qfold,
rejects,
)
+from .theme import THEME

if typing.TYPE_CHECKING:
from typing import (
@@ -718,6 +719,8 @@
self._queueListWidget.customContextMenuRequested.connect(
self._onMenuRequested)
layout.addWidget(self._queueListWidget, 1)
+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(self._queueListWidget)

bbarhbox = QHBoxLayout()
bbarhbox.setSpacing(5)
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/qtlib.py
--- a/tortoisehg/hgqt/qtlib.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/qtlib.py Sun Mar 08 01:48:53 2026 +0100
@@ -39,6 +39,7 @@
pyqtSlot,
)
from .qtgui import (
+ QAbstractItemView,
QAction,
QApplication,
QComboBox,
@@ -62,6 +63,7 @@
QPalette,
QPixmap,
QPushButton,
+ QScrollBar,
QShortcut,
QSizePolicy,
QStyle,
@@ -1854,3 +1856,110 @@
return event.position().toPoint() # pytype: disable=attribute-error
else:
return event.pos() # pytype: disable=attribute-error
+
+
+class CustomScrollBar(QScrollBar):
+ """Work around a Qt stylesheet bug where a large scrollbar could create a dead zone
+ that prevented scrolling to the bottom.
+ The issue occurs when any Scrollbar::handle style parameter is set.
+ """
+
+ def __init__(self, orientation, parent=None):
+ super().__init__(orientation, parent)
+ self._grab_offset = None
+ self._grab_value = None
+
+ def _isVertical(self):
+ return self.orientation() == Qt.Orientation.Vertical
+
+ def _posFromEvent(self, event):
+ return event.pos().y() if self._isVertical() else event.pos().x()
+
+ def mousePressEvent(self, event):
+ if self.maximum() > self.minimum():
+ self._grab_offset = self._posFromEvent(event)
+ self._grab_value = self.value()
+ super().mousePressEvent(event)
+
+ def mouseMoveEvent(self, event):
+ scroll_range = self.maximum() - self.minimum()
+ if self.isSliderDown() and scroll_range > 0 and self._grab_offset is not None:
+ track_length = self.height() if self._isVertical() else self.width()
+ if track_length > 0:
+ delta = self._posFromEvent(event) - self._grab_offset
+ new_position = self._grab_value + (scroll_range + self.pageStep()) * delta / track_length
+ self.setSliderPosition(
+ max(self.minimum(), min(self.maximum(), round(new_position))))
+ return
+ super().mouseMoveEvent(event)
+
+ def mouseReleaseEvent(self, event):
+ self._grab_offset = None
+ self._grab_value = None
+ super().mouseReleaseEvent(event)
+
+
+def _connectScintillaScrollBar(sci, bar, vertical=True):
+ """Sync a replacement scrollbar (vertical or horizontal) with QsciScintilla.
+
+ QsciScintillaBase caches the original scrollbar pointer, so the
+ replacement never gets range updates automatically. We hook
+ SCN_UPDATEUI + textChanged to push range/position into the new bar,
+ and valueChanged to push the bar position back into Scintilla.
+ """
+ _syncing = [False]
+
+ def _sync():
+ if _syncing[0]:
+ return
+ if sip.isdeleted(bar) or sip.isdeleted(sci):
+ return
+ if vertical:
+ total_scroll_range = sci.SendScintilla(sci.SCI_VISIBLEFROMDOCLINE, sci.SendScintilla(sci.SCI_GETLINECOUNT))
+ visible_range = sci.SendScintilla(sci.SCI_LINESONSCREEN)
+ step, pos_msg = 1, sci.SCI_GETFIRSTVISIBLELINE
+ else:
+ total_scroll_range = sci.SendScintilla(sci.SCI_GETSCROLLWIDTH)
+ visible_range = sci.viewport().width()
+ step, pos_msg = 20, sci.SCI_GETXOFFSET
+ if visible_range <= 0:
+ return
+ _syncing[0] = True
+ bar.setRange(0, max(0, total_scroll_range - visible_range))
+ bar.setPageStep(max(1, visible_range))
+ bar.setSingleStep(step)
+ bar.setValue(sci.SendScintilla(pos_msg))
+ _syncing[0] = False
+
+ def _onBarChanged(val):
+ if sip.isdeleted(bar) or sip.isdeleted(sci):
+ return
+ if not _syncing[0]:
+ _syncing[0] = True
+ msg = sci.SCI_SETFIRSTVISIBLELINE if vertical else sci.SCI_SETXOFFSET
+ sci.SendScintilla(msg, val)
+ _syncing[0] = False
+
+ bar.valueChanged.connect(_onBarChanged)
+ sci.SCN_UPDATEUI.connect(lambda *_: _sync())
+ sci.textChanged.connect(_sync)
+ from .qtcore import QTimer
+ QTimer.singleShot(0, _sync)
+
+
+def applyCustomScrollBars(widget):
+
+ # Replace default scrollbars with custom ones
+ vbar = CustomScrollBar(Qt.Orientation.Vertical)
+ hbar = CustomScrollBar(Qt.Orientation.Horizontal)
+ widget.setVerticalScrollBar(vbar)
+ widget.setHorizontalScrollBar(hbar)
+
+ if isinstance(widget, QAbstractItemView):
+ # Reconnect valueChanged signals to preserve lazy-loading (fetchMore) behavior for RepoView.
+ vbar.valueChanged.connect(widget.verticalScrollbarValueChanged)
+ hbar.valueChanged.connect(widget.horizontalScrollbarValueChanged)
+ elif hasattr(widget, 'SendScintilla'):
+ # Set up bidirectional sync: push Scintilla range/position to bar, and bar changes back to Scintilla
+ _connectScintillaScrollBar(widget, vbar, vertical=True)
+ _connectScintillaScrollBar(widget, hbar, vertical=False)
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/rejects.py
--- a/tortoisehg/hgqt/rejects.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/rejects.py Sun Mar 08 01:48:53 2026 +0100
@@ -87,6 +87,8 @@
self.updating = True
self.chunklist.currentRowChanged.connect(self.showChunk)
hbox.addWidget(self.chunklist, 1)
+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(self.chunklist)

bvbox = QVBoxLayout()
bvbox.setContentsMargins(2, 2, 2, 2)
@@ -166,6 +168,8 @@
editor.setSelectionBackgroundColor(THEME.selection_background)
editor.setSelectionForegroundColor(THEME.selection_text)

+ qtlib.applyCustomScrollBars(editor)
+
buf = util.bytesio()
try:
buf.write(b'diff -r aaaaaaaaaaaa -r bbbbbbbbbbb %s\n' % path)
@@ -345,6 +349,8 @@
# Caret
self.setCaretForegroundColor(THEME.caret_foreground)

+ qtlib.applyCustomScrollBars(self)
+
def showChunk(self, lines):
utext = []
added = []
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/reporegistry.py
--- a/tortoisehg/hgqt/reporegistry.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/reporegistry.py Sun Mar 08 01:48:53 2026 +0100
@@ -58,6 +58,7 @@
repotreemodel,
settings,
)
+from .theme import THEME

def settingsfilename():
"""Return path to thg-reporegistry.xml as unicode"""
@@ -95,6 +96,9 @@
| QAbstractItemView.EditTrigger.EditKeyPressed)
self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)

+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(self)
+
def dragEnterEvent(self, event):
if event.source() is self:
# Use the default event handler for internal dragging
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/repoview.py
--- a/tortoisehg/hgqt/repoview.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/repoview.py Sun Mar 08 01:48:53 2026 +0100
@@ -141,6 +141,9 @@
if repoagent.configBool('tortoisehg', 'copy_hash_selection'):
self.clicked.connect(self._copyHashToSelection)

+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(self)
+
@property
def repo(self):
return self._repoagent.rawRepo()
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/resolve.py
--- a/tortoisehg/hgqt/resolve.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/resolve.py Sun Mar 08 01:48:53 2026 +0100
@@ -52,6 +52,7 @@
thgrepo,
visdiff,
)
+from .theme import THEME

if typing.TYPE_CHECKING:
from typing import (
@@ -146,6 +147,8 @@
self.utree.setSelectionMode(QTreeView.SelectionMode.ExtendedSelection)
self.utree.setSortingEnabled(True)
hbox.addWidget(self.utree)
+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(self.utree)

self.utree.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.utreecmenu = QMenu(self)
@@ -200,6 +203,8 @@
self.rtree.setSelectionMode(QTreeView.SelectionMode.ExtendedSelection)
self.rtree.setSortingEnabled(True)
hbox.addWidget(self.rtree)
+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(self.rtree)

self.rtree.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.rtreecmenu = QMenu(self)
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/revdetails.py
--- a/tortoisehg/hgqt/revdetails.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/revdetails.py Sun Mar 08 01:48:53 2026 +0100
@@ -60,6 +60,7 @@
qtlib,
status,
)
+from .theme import THEME
from .filelistview import HgFileListView
from .fileview import HgFileView
from .revpanel import RevPanelWidget
@@ -187,6 +188,9 @@
self.message.setFont(f.font())
f.changed.connect(self.forwardFont)

+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(self.message)
+
self.fileview = HgFileView(self._repoagent, self.messagesplitter)
self.messagesplitter.setStretchFactor(1, 1)
self.fileview.setMinimumSize(QSize(0, 0))
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/settings.py
--- a/tortoisehg/hgqt/settings.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/settings.py Sun Mar 08 01:48:53 2026 +0100
@@ -86,6 +86,7 @@
qtlib,
thgrepo,
)
+from .theme import THEME

if typing.TYPE_CHECKING:
from typing import (
@@ -1524,6 +1525,8 @@
stack = QStackedWidget()
bothbox.addWidget(pageList, 0)
bothbox.addWidget(stack, 1)
+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(pageList)
pageList.currentRowChanged.connect(self.activatePage)

self.pages = {}
@@ -1535,6 +1538,8 @@
desctext.setOpenExternalLinks(True)
layout.addWidget(desctext, 2)
self.desctext = desctext
+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(desctext)

self.settings = QSettings()

diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/status.py
--- a/tortoisehg/hgqt/status.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/status.py Sun Mar 08 01:48:53 2026 +0100
@@ -208,6 +208,7 @@

if THEME.enabled:
tv.setItemDelegate(WctxPreserveStatusColorDelegate(tv))
+ qtlib.applyCustomScrollBars(tv)

vbox.addLayout(hbox)
vbox.addWidget(tv)
diff -r ec21747b1e33 -r 5a7d494b3fb1 tortoisehg/hgqt/sync.py
--- a/tortoisehg/hgqt/sync.py Sun Mar 08 01:36:33 2026 +0100
+++ b/tortoisehg/hgqt/sync.py Sun Mar 08 01:48:53 2026 +0100
@@ -83,6 +83,7 @@
resolve,
thgrepo,
)
+from .theme import THEME

if typing.TYPE_CHECKING:
from typing import (
@@ -1632,6 +1633,9 @@
self.setSelectionMode(QTreeView.SelectionMode.SingleSelection)
self.editable = editable

+ if THEME.enabled:
+ qtlib.applyCustomScrollBars(self)
+
def contextMenuEvent(self, event):
for index in self.selectedRows():
alias = index.data(Qt.ItemDataRole.DisplayRole)

Reply all
Reply to author
Forward
0 new messages