From 08255e7cdeb8edff498e854e8f59673051840b6c Mon Sep 17 00:00:00 2001 From: Kenneth Chew <79120643+kthchew@users.noreply.github.com> Date: Wed, 31 May 2023 11:13:59 -0400 Subject: [PATCH] gui: improve usability in dark mode (bug 1719424) (#1290) --- gui/icons/cross106_white.png | Bin 0 -> 4498 bytes gui/icons/cutting10_white.png | Bin 0 -> 4724 bytes gui/icons/letter52_white.png | Bin 0 -> 4868 bytes gui/mozregui/mainwindow.py | 22 ++++++++++++++- gui/mozregui/report.py | 13 ++++++++- gui/mozregui/report_delegate.py | 47 +++++++++++++++++++++++--------- gui/mozregui/skip_chooser.py | 18 ++++++++++-- gui/mozregui/utils.py | 8 ++++++ gui/resources.qrc | 3 ++ 9 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 gui/icons/cross106_white.png create mode 100644 gui/icons/cutting10_white.png create mode 100644 gui/icons/letter52_white.png diff --git a/gui/icons/cross106_white.png b/gui/icons/cross106_white.png new file mode 100644 index 0000000000000000000000000000000000000000..b239fedc8491bba02dcb78ef8f0a88b78d060870 GIT binary patch literal 4498 zcmeHKdsGuw8c&phfV8!MT94uwK*V-3$s{D1St0^Kh#1HM0#>U`W+pH~9wdW_xJ3$X zTaZ_Mte{jupzgA2ON$nK6^f5;Idw(1R*MS7<$%@|d+I7%tlc}|ecE&Oc+U1ek~5jP z-~G++`@Y}z-FtEiv@ww$Zu8uDJf4R-N)-q05O>XR2EW$q?1$iXK06_qjU#N3*<#W& z88pOhHq#JoXY@Rt{TqX})uT-`-TF0g?HwtY1&fv|W8JYN+q0 zm8JZpl}*CSjmI)l=sIHo6?ve6+Mk&h_R){$55+?@De_ahW)Hk@rqVeltNre|sQrr$ z+d{D?y%(0`Z0qRg*SY(8_?Ef*&pc7Od*2t91;ouC7W4!Zf7npE{vXG>_Ri_Nm00Z5 zQIeN2E5*dS4OOrGY_==v^Uc@4?^wLGXrudoJ~=e~j{B^xHMz0X&Y?UWKc5K?*Q&$A zM>7I>RKD@9GOBI){Bs+wtlXY3{~mO(tQx-_QKz`N)T=t|&)%KAOF5U@LV5=MErI{6 z&wZEV2c?xQ2pL@X{kH(fsY^fmYL zpZrc=|LS05OSjCNdGo7X%5ICx+?@LMx9&yd>ORu;< z(XZE;a`VGe4yvwy=QHs9zaKpssEFAbQru=~I8%K12xz=)1~gc*W))7F3_^l3>1d(d zUiNkJNs#vD$kF;UqTIzBrlfy_=PF-j1! z%q`fC0|Eoh5|G`HVYK3QrNF_9gJ;f+2p|W9O;-w%HCia#WT7FcP%0F`5q4%1Dp=+Q z1zRXR9;aF{LIFlfK^n`NaRjm1Y(kqvXtJatVhqC&5sIKF3=pt&vymn2u+i$vQ4Dja zXe()9%q(LvLL4WdGi9+#fdI@yqwyKc8qFBJ(K@06&;zj(W<)F$AqE37@eL~*u?dij z1oW$KSQEfHMdE0yDa%6A5u0cu>pPJmQmxUBF>ooRG6u6FDIne?XB0VxGiO;c92km3 z=nUEbNUb0~@gzLU=*PvH6dO0=NM~Xoz}*=CB=l(R4lqDzG`Pw{W^qo{Dy4vn7pF`l zL*b4`R7&XxQbEBqEtkMjnNAF2m|h0U2@E5}dQ?P6sR>kSqm?C$B+XF)av=kFbeK*j z!3aI9&|?%V1%xmmmC0d+Or}T4AiYeXBPUSAS{TrkM8?FZI4a6P6(m7vg&Y=(DLE_^ z$rLa_>VsfRPs=cjlA=MB#6iW?0T0!xl>$^K8nh7?c7HK|-dSi#8&`H0(1^zAW~_>Y)o}baCN~! zHb7Z|YgEAOu!Cgqa0^YaCQE|Jl%W)G!9pD6*t7<$CyHPR6~WTLn+TQQA}Nk45>ONm zlHsBt7z{-d@Ft4UZ~k9sZuLOH!!?g$tib7?21aS4=*l7&4ME!tENP zDF-9J5GB|Fn6S-&_l9j?`vSWmGPWI#hz0`wEk7g0_$^&P(3F#B(sxR(DY>3WfoB3w zb=Qvp=HY^o{vL#B&oZ_jg!cbrQt@VWTeGeUKhamc<;>|d=jv*%0DXBp NbwrHnXjn?#e*udrc9{SG literal 0 HcmV?d00001 diff --git a/gui/icons/cutting10_white.png b/gui/icons/cutting10_white.png new file mode 100644 index 0000000000000000000000000000000000000000..50f7017c19e2f31bd4fb5343123c25e06e1e2359 GIT binary patch literal 4724 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 db><-Xm2EoT bool: + if event.type() == QEvent.PaletteChange: + self._update_palette() + return True + + return super().event(event) diff --git a/gui/mozregui/report.py b/gui/mozregui/report.py index 942dbb2d5..a97477fe4 100644 --- a/gui/mozregui/report.py +++ b/gui/mozregui/report.py @@ -3,14 +3,20 @@ from PySide6.QtWidgets import QTableView, QTextBrowser from mozregression.bisector import NightlyHandler +from mozregui.utils import is_dark_mode_enabled # Custom colors GRAY_WHITE = QColor(243, 243, 243) +DARK_GRAY = QColor(28, 28, 28) VERDICT_TO_ROW_COLORS = { "g": QColor(152, 251, 152), # light green "b": QColor(250, 113, 113), # light red "s": QColor(253, 248, 107), # light yellow "r": QColor(225, 225, 225), # light gray + "g_dark": QColor(48, 209, 88), # green + "b_dark": QColor(255, 70, 58), # red + "s_dark": QColor(160, 90, 0), # yellow + "r_dark": QColor(45, 45, 45), # gray } @@ -167,7 +173,12 @@ def data(self, index, role=Qt.DisplayRole): return item.status_text() elif role == Qt.BackgroundRole: if isinstance(item, StepItem) and item.verdict: - return VERDICT_TO_ROW_COLORS.get(str(item.verdict), GRAY_WHITE) + if is_dark_mode_enabled(): + return VERDICT_TO_ROW_COLORS.get(str(item.verdict) + "_dark", DARK_GRAY) + else: + return VERDICT_TO_ROW_COLORS.get(str(item.verdict), GRAY_WHITE) + elif is_dark_mode_enabled(): + return DARK_GRAY else: return GRAY_WHITE diff --git a/gui/mozregui/report_delegate.py b/gui/mozregui/report_delegate.py index 7bf4d4a60..88cc2994b 100644 --- a/gui/mozregui/report_delegate.py +++ b/gui/mozregui/report_delegate.py @@ -1,5 +1,5 @@ -from PySide6.QtCore import QRect, Qt, Signal -from PySide6.QtGui import QIcon, QPainter, QPixmap +from PySide6.QtCore import QEvent, QRect, Qt, Signal +from PySide6.QtGui import QIcon, QPainter, QPen, QPixmap from PySide6.QtWidgets import ( QApplication, QStyle, @@ -10,6 +10,7 @@ from mozregui.report import VERDICT_TO_ROW_COLORS from mozregui.ui.ask_verdict import Ui_AskVerdict +from mozregui.utils import is_dark_mode_enabled VERDICTS = ("good", "bad", "skip", "retry", "other...") @@ -25,17 +26,7 @@ def __init__(self, parent, delegate): self.ui.setupUi(self) # build verdict icons if not AskVerdict.icons_cache: - for text in VERDICTS: - color = VERDICT_TO_ROW_COLORS.get(text[0]) - pixmap = QPixmap(16, 16) - pixmap.fill(Qt.transparent) - if color: - painter = QPainter(pixmap) - painter.setPen(Qt.black) - painter.setBrush(color) - painter.drawEllipse(0, 0, 15, 15) - painter.end() - AskVerdict.icons_cache[text] = QIcon(pixmap) + self._build_icon_cache() # set combo verdict for text in ("other...", "skip", "retry"): @@ -51,6 +42,29 @@ def __init__(self, parent, delegate): self.ui.badVerdict.clicked.connect(self.on_good_bad_button_clicked) self.ui.badVerdict.setIcon(AskVerdict.icons_cache["bad"]) + def _build_icon_cache(self): + for text in VERDICTS: + if is_dark_mode_enabled(): + color = VERDICT_TO_ROW_COLORS.get(text[0] + "_dark") + else: + color = VERDICT_TO_ROW_COLORS.get(text[0]) + pixmap = QPixmap(16, 16) + pixmap.fill(Qt.transparent) + if color: + painter = QPainter(pixmap) + painter.setPen(QPen(self.palette().windowText().color())) + painter.setBrush(color) + painter.drawEllipse(0, 0, 15, 15) + painter.end() + AskVerdict.icons_cache[text] = QIcon(pixmap) + + def _update_icons(self): + self.ui.goodVerdict.setIcon(AskVerdict.icons_cache["good"]) + self.ui.badVerdict.setIcon(AskVerdict.icons_cache["bad"]) + for i in range(self.ui.comboVerdict.count()): + text = str(self.ui.comboVerdict.itemText(i)) + self.ui.comboVerdict.setItemIcon(i, AskVerdict.icons_cache[text]) + def on_dropdown_item_activated(self): self.delegate.got_verdict.emit(str(self.ui.comboVerdict.currentText())[0].lower()) self.emitted = True @@ -59,6 +73,13 @@ def on_good_bad_button_clicked(self): self.delegate.got_verdict.emit(str(self.sender().text())[0].lower()) self.emitted = True + def event(self, event: QEvent) -> bool: + if event.type() == QEvent.PaletteChange: + self._build_icon_cache() + self._update_icons() + return True + return super().event(event) + class ReportItemDelegate(QStyledItemDelegate): got_verdict = Signal(str) diff --git a/gui/mozregui/skip_chooser.py b/gui/mozregui/skip_chooser.py index 5b50bbcbd..578e77bce 100644 --- a/gui/mozregui/skip_chooser.py +++ b/gui/mozregui/skip_chooser.py @@ -1,5 +1,5 @@ -from PySide6.QtCore import Qt, Signal -from PySide6.QtGui import QBrush +from PySide6.QtCore import QEvent, Qt, Signal +from PySide6.QtGui import QBrush, QPen from PySide6.QtWidgets import ( QDialog, QGraphicsRectItem, @@ -53,8 +53,22 @@ def from_range(self, build_range): self.mid_build = item elif i in bounds: item.setBrush(QBrush(Qt.lightGray)) + + pen = QPen(self.palette().windowText().color()) + item.setPen(pen) self.addItem(item) + def _update_palette(self): + for item in self.items(): + pen = QPen(self.palette().windowText().color()) + item.setPen(pen) + + def event(self, event: QEvent) -> bool: + if event.type() == QEvent.PaletteChange: + self._update_palette() + return True + return super().event(event) + class SkipChooserView(QGraphicsView): build_choosen = Signal() diff --git a/gui/mozregui/utils.py b/gui/mozregui/utils.py index 7a1b1749e..e562ae410 100644 --- a/gui/mozregui/utils.py +++ b/gui/mozregui/utils.py @@ -1,4 +1,5 @@ from PySide6.QtCore import QDir +from PySide6.QtGui import QGuiApplication, QPalette from PySide6.QtWidgets import ( QCompleter, QFileDialog, @@ -85,3 +86,10 @@ def get_value(self): raise DateFormatError(buildid, "Not a valid build id: `%s`") elif currentw == self.ui.s_changeset: return self.ui.changeset.text().strip() + + +def is_dark_mode_enabled(): + """ + Return True if dark mode is being used. + """ + return QGuiApplication.palette().color(QPalette.Window).lightness() < 128 diff --git a/gui/resources.qrc b/gui/resources.qrc index 6b5110bba..babc36cbe 100644 --- a/gui/resources.qrc +++ b/gui/resources.qrc @@ -4,5 +4,8 @@ icons/cross106.png icons/cutting10.png icons/letter52.png + icons/cross106_white.png + icons/cutting10_white.png + icons/letter52_white.png