Skip to content

Commit

Permalink
Gtk3 Theme: Fix disabled colors for texts
Browse files Browse the repository at this point in the history
Previously, disabled text colors were a darker version of the normal
text color. However, when the text color is black, the darker version
is also black, making the disabled text indistinguishable from the
enabled text.

To fix this issue, a source struct called `MixSources` has been
implemented. This struct contains the mixing sources. For disabled
texts, a mix of the background and text color sources creates a more
sensible appearance, making the disabled text look more like the
control's background color.

This solution does not require access to the system's color scheme, as
the disabled color depends only on the background and foreground colors.

Fixes: QTBUG-123449
Pick-to: 6.8 6.7 6.5
Change-Id: I469e4fc05ddd4851120b89646bd7ab17a3ee2c00
Reviewed-by: Volker Hilsheimer <[email protected]>
Reviewed-by: Axel Spoerl <[email protected]>
  • Loading branch information
MohammadHossein Qanbari committed Jul 1, 2024
1 parent bcfa010 commit 21a0700
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 5 deletions.
29 changes: 29 additions & 0 deletions src/plugins/platformthemes/gtk3/qgtk3json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,15 @@ const QJsonDocument QGtk3Json::save(const QGtk3Storage::PaletteMap &map)
}
break;

case QGtk3Storage::SourceType::Mixed: {
sourceObject.insert(ceColorGroup, fromColorGroup(s.mix.sourceGroup));
QJsonArray colorRoles;
colorRoles << fromColorRole(s.mix.colorRole1)
<< fromColorRole(s.mix.colorRole2);
sourceObject.insert(ceColorRole, colorRoles);
}
break;

case QGtk3Storage::SourceType::Invalid:
break;
}
Expand Down Expand Up @@ -387,6 +396,26 @@ bool QGtk3Json::load(QGtk3Storage::PaletteMap &map, const QJsonDocument &doc)
}
break;

case QGtk3Storage::SourceType::Mixed: {
if (!sourceObject[ceColorRole].isArray()) {
qCInfo(lcQGtk3Interface) << "Mixed brush missing the array of color roles for palette:" << paletteName
<< "Brush" << colorRoleName;
return false;
}
QJsonArray colorRoles = sourceObject[ceColorRole].toArray();
if (colorRoles.size() < 2) {
qCInfo(lcQGtk3Interface) << "Mixed brush missing enough color roles for palette" << paletteName
<< "Brush" << colorRoleName;
return false;
}
const QPalette::ColorRole colorRole1 = toColorRole(colorRoles[0].toString());
const QPalette::ColorRole colorRole2 = toColorRole(colorRoles[1].toString());
GETSTR(sourceObject, ceColorGroup);
const QPalette::ColorGroup sourceGroup = toColorGroup(value);
s = QGtk3Storage::Source(sourceGroup, colorRole1, colorRole2);
}
break;

case QGtk3Storage::SourceType::Invalid:
qInfo(lcQGtk3Interface) << "Invalid source type for palette" << paletteName
<< "Brush." << colorRoleName;
Expand Down
46 changes: 42 additions & 4 deletions src/plugins/platformthemes/gtk3/qgtk3storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,31 @@ QBrush QGtk3Storage::brush(const Source &source, const BrushMap &map) const
return b;
}

case SourceType::Mixed: {
// check the mixing source to be valid and be a Gtk source
constexpr auto check_source = [](const Source &source) -> bool
{
return source.isValid() && (source.sourceType == SourceType::Gtk);
};

const Source source1 = brush(TargetBrush(source.mix.sourceGroup,
source.mix.colorRole1), map);
if (!check_source(source1))
return QBrush();

const Source source2 = brush(TargetBrush(source.mix.sourceGroup,
source.mix.colorRole2), map);
if (!check_source(source2))
return QBrush();

const QBrush brush2 = brush(source2, map);
// the output brush is a copy of the brush from the first source
QBrush brush1 = brush(source1, map);
// only color is mixed
brush1.setColor(MixSources::mixColors(brush1.color(), brush2.color()));
return brush1;
}

case SourceType::Fixed:
return source.fix.fixedBrush;

Expand Down Expand Up @@ -413,6 +438,7 @@ const QGtk3Storage::PaletteMap QGtk3Storage::savePalettes() const
break;
case SourceType::Fixed:
case SourceType::Modified:
case SourceType::Mixed:
case SourceType::Invalid:
break;
}
Expand Down Expand Up @@ -554,10 +580,22 @@ void QGtk3Storage::createMapping()

GTK(button, Foreground, ACTIVE);
ADD(Inactive, WindowText);
LIGHTER(Normal, WindowText, 50);
ADD(Disabled, Text);
ADD(Disabled, WindowText);
ADD(Disabled, ButtonText);

auto ADD_MIX = [&map](QPalette::ColorGroup targetGroup,
QPalette::ColorRole targetRole,
QPalette::ColorGroup sourceGroup,
QPalette::ColorRole role1,
QPalette::ColorRole role2)
{
const Source source{sourceGroup, role1, role2};
map.insert(TargetBrush(targetGroup, targetRole), source);
};
ADD_MIX(QPalette::Disabled, QPalette::Text,
QPalette::Normal, QPalette::Base, QPalette::Text);
ADD_MIX(QPalette::Disabled, QPalette::WindowText,
QPalette::Normal, QPalette::Window, QPalette::WindowText);
ADD_MIX(QPalette::Disabled, QPalette::ButtonText,
QPalette::Normal, QPalette::Button, QPalette::ButtonText);

GTK(button, Text, NORMAL);
ADD(Inactive, ButtonText);
Expand Down
35 changes: 34 additions & 1 deletion src/plugins/platformthemes/gtk3/qgtk3storage_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class QGtk3Storage
Gtk,
Fixed,
Modified,
Mixed,
Invalid
};
Q_ENUM(SourceType)
Expand Down Expand Up @@ -80,6 +81,27 @@ class QGtk3Storage
}
};

// Mixed source: Populate a brush by mixing two brushes.
// Useful for creating disabled color by mixing,
// for example the background and foreground colors.
struct MixSources {
QPalette::ColorGroup sourceGroup; // source group of the mixing color roles
QPalette::ColorRole colorRole1;
QPalette::ColorRole colorRole2;
QDebug operator<<(QDebug dbg)
{
return dbg << "QGtkStorage::MixSources(sourceGroup=" << sourceGroup
<< ", colorRole1=" << colorRole1
<< ", colorRole2=" << colorRole2 << ")";
}
static inline QColor mixColors(const QColor &color1, const QColor &color2)
{
return QColor{ (color1.red() + color2.red()) / 2,
(color1.green() + color2.green()) / 2,
(color1.blue() + color2.blue()) / 2 };
}
};

// Fixed source: Populate a brush with fixed values rather than reading GTK
struct FixedSource {
QBrush fixedBrush;
Expand All @@ -95,6 +117,7 @@ class QGtk3Storage
Gtk3Source gtk3;
RecursiveSource rec;
FixedSource fix;
MixSources mix;

// GTK constructor
Source(QGtk3Interface::QGtkWidget wtype, QGtk3Interface::QGtkColorSource csource,
Expand All @@ -118,7 +141,7 @@ class QGtk3Storage
rec.lighter = p_lighter;
}

// Recursive ocnstructor for color modification
// Recursive constructor for color modification
Source(QPalette::ColorGroup group, QPalette::ColorRole role,
Qt::ColorScheme scheme, int p_red, int p_green, int p_blue)
: sourceType(SourceType::Modified)
Expand All @@ -145,6 +168,16 @@ class QGtk3Storage
rec.deltaBlue = p_blue;
}

// Mixed constructor for color modification
Source(QPalette::ColorGroup sourceGroup,
QPalette::ColorRole role1, QPalette::ColorRole role2)
: sourceType(SourceType::Mixed)
{
mix.sourceGroup = sourceGroup;
mix.colorRole1 = role1;
mix.colorRole2 = role2;
}

// Fixed Source constructor
Source(const QBrush &brush) : sourceType(SourceType::Fixed)
{
Expand Down

0 comments on commit 21a0700

Please sign in to comment.