Qt: Use a lighter link color in dark mode.

Add ColorUtils::themeLinkBrush, which returns a readable link color in
dark mode. Use it in place of existing ...palette().link() calls.

Add ColorUtils::themeLinkStyle, which produces an HTML <style/> block
that lightens the link foreground color in dark mode. Use this to style
links in the about box and in elided labels.

Catch ApplicationPaletteChange events where needed.

Add dark theme / dark mode notes to the WSDG.

Ping-Bug: 15511
Change-Id: I92925bd997f97b155491f55a8c818f03549bc7f4
Reviewed-on: https://code.wireshark.org/review/33704
Petri-Dish: Gerald Combs <gerald@wireshark.org>
Tested-by: Petri Dish Buildbot
Reviewed-by: Gerald Combs <gerald@wireshark.org>
This commit is contained in:
Gerald Combs 2019-06-21 16:47:06 -07:00
parent cbcb50e8af
commit 94f497f929
10 changed files with 114 additions and 24 deletions

View File

@ -223,7 +223,7 @@ code through the following steps:
- push and commit on Gerrit
- push ts on Transifex
===== Colors
===== Colors And Themes
Qt provides a number of colors via the http://doc.qt.io/qt-5/qpalette.html[QPalette]
class. Use this class when you need a standard color provided by the
@ -236,6 +236,20 @@ I/O graphs, sequence diagrams, and RTP streams. Please use this palette
(defined in `tango_colors.h` and the *ColorUtils* class) if *QPalette*
doesn't meet your needs.
Wireshark supports dark themes (aka “dark mode”) on some platforms. We
leverage Qt's dark theme support when possible, but have implemented our
own support and workarounds in some cases. You can ensure that your code
includes proper dark theme support by doing the following:
* You can use a macOS-style template icon by creating a monochrome SVG
document with “.template” appended to the name, e.g.
`image/stock_icons/24x24/edit-find.template.svg`.
* Qt draws unvisited links *Qt::blue* no matter what. You can work
around this by using `ColorUtils::themeLinkBrush()` and
`ColorUtils::themeLinkStyle()`.
* You can catch dark and light mode changes by handling
`QEvent::ApplicationPaletteChange`.
==== Other Issues and Information
The main window has many QActions which are shared with child widgets. See

View File

@ -44,8 +44,10 @@
#include "extcap.h"
#include <ui/qt/utils/color_utils.h>
#include <ui/qt/utils/qt_ui_utils.h>
#include <ui/qt/utils/variant_pointer.h>
#include <ui/qt/models/astringlist_list_model.h>
#include <ui/qt/models/url_link_delegate.h>
@ -268,14 +270,6 @@ AboutDialog::AboutDialog(QWidget *parent) :
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose, true);
QFile f_license;
QString message;
QString vcs_version_info_str = get_ws_vcs_version_info();
QString copyright_info_str = get_copyright_info();
QString comp_info_str = gstring_free_to_qbytearray(get_compiled_version_info(get_wireshark_qt_compiled_info,
get_gui_compiled_info));
QString runtime_info_str = gstring_free_to_qbytearray(get_runtime_version_info(get_wireshark_runtime_info));
AuthorListModel * authorModel = new AuthorListModel(this);
AStringListListSortFilterProxyModel * proxyAuthorModel = new AStringListListSortFilterProxyModel(this);
@ -294,20 +288,10 @@ AboutDialog::AboutDialog(QWidget *parent) :
connect(ui->searchAuthors, SIGNAL(textChanged(QString)), proxyAuthorModel, SLOT(setFilter(QString)));
/* Wireshark tab */
/* Construct the message string */
message = "<p>Version " + html_escape(vcs_version_info_str) + "</p>\n\n";
message += "<p>" + html_escape(copyright_info_str) + "</p>\n\n";
message += "<p>" + html_escape(comp_info_str) + "</p>\n\n";
message += "<p>" + html_escape(runtime_info_str) + "</p>\n\n";
message += "<p>Wireshark is Open Source Software released under the GNU General Public License.</p>\n\n";
message += "<p>Check the man page and ";
message += "<a href=https://www.wireshark.org>https://www.wireshark.org</a> ";
message += "for more information.</p>\n\n";
updateWiresharkText();
ui->pte_wireshark->setFrameStyle(QFrame::NoFrame);
ui->pte_wireshark->viewport()->setAutoFillBackground(false);
ui->pte_wireshark->setHtml(message);
/* Check if it is a dev release... (VERSION_MINOR is odd in dev release) */
#if VERSION_MINOR & 1
@ -397,6 +381,19 @@ AboutDialog::~AboutDialog()
delete ui;
}
bool AboutDialog::event(QEvent *event)
{
switch (event->type()) {
case QEvent::ApplicationPaletteChange:
updateWiresharkText();
break;
default:
break;
}
return QDialog::event(event);
}
void AboutDialog::showEvent(QShowEvent * event)
{
int one_em = fontMetrics().height();
@ -429,6 +426,28 @@ void AboutDialog::showEvent(QShowEvent * event)
QDialog::showEvent(event);
}
void AboutDialog::updateWiresharkText()
{
QString vcs_version_info_str = get_ws_vcs_version_info();
QString copyright_info_str = get_copyright_info();
QString comp_info_str = gstring_free_to_qbytearray(get_compiled_version_info(get_wireshark_qt_compiled_info,
get_gui_compiled_info));
QString runtime_info_str = gstring_free_to_qbytearray(get_runtime_version_info(get_wireshark_runtime_info));
QString message = ColorUtils::themeLinkStyle();
/* Construct the message string */
message += "<p>Version " + html_escape(vcs_version_info_str) + "</p>\n\n";
message += "<p>" + html_escape(copyright_info_str) + "</p>\n\n";
message += "<p>" + html_escape(comp_info_str) + "</p>\n\n";
message += "<p>" + html_escape(runtime_info_str) + "</p>\n\n";
message += "<p>Wireshark is Open Source Software released under the GNU General Public License.</p>\n\n";
message += "<p>Check the man page and ";
message += "<a href=https://www.wireshark.org>https://www.wireshark.org</a> ";
message += "for more information.</p>\n\n";
ui->pte_wireshark->setHtml(message);
}
void AboutDialog::urlDoubleClicked(const QModelIndex &idx)
{
if (idx.column() != 1) {

View File

@ -87,9 +87,12 @@ public:
~AboutDialog();
protected:
virtual bool event(QEvent *event);
virtual void showEvent(QShowEvent *);
private:
void updateWiresharkText();
Ui::AboutDialog *ui;
QString script_pattern;

View File

@ -15,6 +15,8 @@
#include <ui/qt/models/astringlist_list_model.h>
#include <ui/qt/utils/color_utils.h>
AStringListListModel::AStringListListModel(QObject * parent):
QAbstractTableModel(parent)
{}
@ -187,7 +189,7 @@ QVariant AStringListListUrlProxyModel::data(const QModelIndex &index, int role)
if ( result.canConvert(QVariant::Brush) )
{
QBrush selected = result.value<QBrush>();
selected.setColor(QApplication::palette().link().color());
selected.setColor(ColorUtils::themeLinkBrush().color());
return selected;
}
} else if ( role == Qt::TextColorRole ) {

View File

@ -123,7 +123,7 @@ QVariant ProtoTreeModel::data(const QModelIndex &index, int role) const
return ColorUtils::expert_color_foreground;
}
if (finfo.isLink()) {
return QApplication::palette().link();
return ColorUtils::themeLinkBrush();
}
if(finfo.headerInfo().type == FT_PROTOCOL) {
return QApplication::palette().windowText();

View File

@ -13,6 +13,8 @@
#include <QPainter>
#include <QRegExp>
#include <ui/qt/utils/color_utils.h>
UrlLinkDelegate::UrlLinkDelegate(QObject *parent)
: QStyledItemDelegate(parent),
re_col_(-1),
@ -44,7 +46,7 @@ void UrlLinkDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio
initStyleOption(&opt, index);
opt.font.setUnderline(true);
opt.palette.setColor(QPalette::Text, opt.palette.link().color());
opt.palette.setColor(QPalette::Text, ColorUtils::themeLinkBrush().color());
QStyledItemDelegate::paint(painter, opt, index);
}

View File

@ -146,6 +146,37 @@ bool ColorUtils::themeIsDark()
return wsApp->palette().windowText().color().lightness() > wsApp->palette().window().color().lightness();
}
// As of 5.12.3, Qt always uses Qt::blue for the link color, which is
// unreadable when using a dark theme. Changing the application palette
// via ...Application::setPalette is problematic, since QGuiApplication
// sets a flag (ApplicationPaletteExplicitlySet) which keeps us from
// catching theme changes.
//
// themeLinkBrush and themeLinkStyle provide convenience routines for
// fetching the link brush and style. We can remove them if Qt ever fixes
// the link color.
//
// We could also override WiresharkApplication::palette, but keeping the
// routines together here seemed to make more sense.
QBrush ColorUtils::themeLinkBrush()
{
if (themeIsDark()) {
return QBrush(tango_sky_blue_2);
}
return wsApp->palette().link();
}
QString ColorUtils::themeLinkStyle()
{
QString link_style;
if (themeIsDark()) {
link_style = QString("<style>a:link { color: %1; }</style>")
.arg(themeLinkBrush().color().name());
}
return link_style;
}
/*
* Editor modelines
*

View File

@ -52,6 +52,8 @@ public:
* @return true if we're running in dark mode, false otherwise.
*/
static bool themeIsDark();
static QBrush themeLinkBrush();
static QString themeLinkStyle();
signals:

View File

@ -9,6 +9,8 @@
#include <ui/qt/widgets/elided_label.h>
#include <ui/qt/utils/color_utils.h>
#include <QFontMetrics>
#include <QResizeEvent>
@ -26,6 +28,19 @@ void ElidedLabel::setUrl(const QString &url)
updateText();
}
bool ElidedLabel::event(QEvent *event)
{
switch (event->type()) {
case QEvent::ApplicationPaletteChange:
updateText();
break;
default:
break;
}
return QLabel::event(event);
}
void ElidedLabel::resizeEvent(QResizeEvent *)
{
updateText();
@ -40,6 +55,7 @@ void ElidedLabel::updateText()
QString label_text = small_text_ ? "<small><i>" : "<i>";
if (url_.length() > 0) {
label_text.prepend(ColorUtils::themeLinkStyle());
label_text.append(QString("<a href=\"%1\">%2</a>")
.arg(url_)
.arg(elided_text)

View File

@ -21,7 +21,8 @@ public:
void setSmallText(bool small_text = true) { small_text_ = small_text; }
protected:
void resizeEvent(QResizeEvent *);
virtual bool event(QEvent *event);
virtual void resizeEvent(QResizeEvent *);
private:
bool small_text_;