on xenial help sign in
Redo text color threshold on backgrounds
commitf7af5522cd91ffee55e40ad5cc891b26996bb318 authorMichał Sawicz <michal.sawicz@canonical.com> dateThu 14 Aug 2014, 18:24 (12 years ago) parent12d39f9
7 files changed+53−73
plugins/Dash/CardCreator.js+2−2 plugins/Dash/ScopeStyle.qml+20−24 tests/plugins/Dash/cardcreator/2.res+2−2 tests/plugins/Dash/cardcreator/5.res+2−2 tests/plugins/Dash/cardcreator/6.res+3−3 tests/plugins/Dash/cardcreator/7.res+3−3 tests/plugins/Dash/tst_ScopeStyle.qml+21−37
plugins/Dash/CardCreator.js+2−2
@@ -439,14 +439,14 @@ function cardString(template, components) {
439439 mascotCode = kMascotImageCode.arg(mascotAnchors).arg(mascotImageVisible);
440440 }
441441
442− var summaryColorWithBackground = 'backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : Theme.palette.normal.baseText)';
442+ var summaryColorWithBackground = 'backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white")';
443443
444444 var hasTitleContainer = hasTitle && (hasEmblem || (hasMascot && (hasSubtitle || hasAttributes)));
445445 var titleSubtitleCode = '';
446446 if (hasTitle) {
447447 var titleColor;
448448 if (headerAsOverlay) {
449− titleColor = 'overlayLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : Theme.palette.normal.baseText)';
449+ titleColor = 'root.scopeStyle ? root.scopeStyle.getTextColor(overlayLoader.item.luminance) : (overlayLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white")';
450450 } else if (hasSummary) {
451451 titleColor = 'summary.color';
452452 } else if (hasBackground) {
plugins/Dash/ScopeStyle.qml+20−24
@@ -16,6 +16,7 @@
1616
1717import QtQuick 2.2
1818import Utils 0.1
19+import Ubuntu.Components 1.1
1920
2021/*! \brief Helper for processing scope customization options.
2122
@@ -40,31 +41,17 @@ QtObject {
4041 /// Luminance of the background color
4142 readonly property real backgroundLuminance: background ? Style.luminance(background) : Style.luminance(d.defaultLight)
4243
43− /*! \brief Luminance threshold for switching between fore and background color
44−
45− \note If background colour is not fully opaque, the defaultLightLuminance it's taken into account instead of it.
44+ /*! \brief Get the most contrasting available color based on luminance
45+ *
46+ * If background color is transparent, theme provided colors are taken into account
4647 */
47− readonly property real threshold: background.a !== 1.0 ? (foregroundLuminance + d.defaultLightLuminance) / 2
48− : (foregroundLuminance + backgroundLuminance) / 2
49−
50− /*! \brief The lighter of foreground and background colors
51−
52− \note If background color is not fully opaque, it's not taken into account
53− and defaults to the theme-provided light color.
54− */
55− readonly property color light: {
56− if (background.a !== 1.0) return foregroundLuminance > d.defaultLightLuminance ? foreground : d.defaultLight;
57− return foregroundLuminance > backgroundLuminance ? foreground : background;
58− }
59−
60− /*! \brief The darker of foreground and background colors
61−
62− \note If background color is not fully opaque, it's not taken into account
63− and defaults to the theme-provided dark color.
64− */
65− readonly property color dark: {
66− if (background.a !== 1.0) return foregroundLuminance < d.defaultDarkLuminance ? foreground : d.defaultDark;
67− return foregroundLuminance < backgroundLuminance ? foreground : background;
48+ function getTextColor(luminance) {
49+ if (Math.abs(foregroundLuminance - luminance) >
50+ Math.abs(d.opaqueBackgroundLuminance - luminance)) {
51+ return foreground;
52+ } else {
53+ return d.opaqueBackground;
54+ }
6855 }
6956
7057 /// Source of the logo image for the header
@@ -93,6 +80,15 @@ QtObject {
9380 readonly property real defaultLightLuminance: Style.luminance(defaultLight)
9481 readonly property real defaultDarkLuminance: Style.luminance(defaultDark)
9582
83+ readonly property color opaqueBackground: {
84+ background.a > 0 ?
85+ background :
86+ (Math.abs(foregroundLuminance - defaultLightLuminance) >
87+ Math.abs(foregroundLuminance - defaultDarkLuminance)) ?
88+ defaultLight : defaultDark
89+ }
90+ readonly property real opaqueBackgroundLuminance: Style.luminance(opaqueBackground)
91+
9692 readonly property var headerStyle: "page-header" in style ? style["page-header"] : { }
9793 }
9894 //! @endcond
tests/plugins/Dash/cardcreator/2.res+2−2
@@ -94,7 +94,7 @@ Image {
9494 wrapMode: Text.Wrap;
9595 maximumLineCount: 2;
9696 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
97− color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : Theme.palette.normal.baseText);
97+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
9898 visible: showHeader ;
9999 text: root.title;
100100 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
@@ -112,7 +112,7 @@ Image {
112112 elide: Text.ElideRight;
113113 fontSize: "small";
114114 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
115− color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : Theme.palette.normal.baseText);
115+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
116116 visible: titleLabel.visible && titleLabel.text;
117117 text: cardData && cardData["subtitle"] || "";
118118 font.weight: Font.Light;
tests/plugins/Dash/cardcreator/5.res+2−2
@@ -113,7 +113,7 @@ Label {
113113 wrapMode: Text.Wrap;
114114 maximumLineCount: 2;
115115 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
116− color: overlayLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : Theme.palette.normal.baseText);
116+ color: root.scopeStyle ? root.scopeStyle.getTextColor(overlayLoader.item.luminance) : (overlayLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
117117 visible: showHeader && overlayLoader.active;
118118 text: root.title;
119119 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
@@ -131,7 +131,7 @@ Label {
131131 elide: Text.ElideRight;
132132 fontSize: "small";
133133 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
134− color: overlayLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : Theme.palette.normal.baseText);
134+ color: root.scopeStyle ? root.scopeStyle.getTextColor(overlayLoader.item.luminance) : (overlayLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
135135 visible: titleLabel.visible && titleLabel.text;
136136 text: cardData && cardData["subtitle"] || "";
137137 font.weight: Font.Light;
tests/plugins/Dash/cardcreator/6.res+3−3
@@ -70,7 +70,7 @@ Item {
7070 wrapMode: Text.Wrap;
7171 maximumLineCount: 2;
7272 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
73− color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : Theme.palette.normal.baseText);
73+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
7474 visible: showHeader ;
7575 text: root.title;
7676 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
@@ -88,7 +88,7 @@ Item {
8888 elide: Text.ElideRight;
8989 fontSize: "small";
9090 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
91− color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : Theme.palette.normal.baseText);
91+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
9292 visible: titleLabel.visible && titleLabel.text;
9393 text: cardData && cardData["subtitle"] || "";
9494 font.weight: Font.Light;
@@ -103,7 +103,7 @@ Item {
103103 rightMargin: units.gu(1);
104104 }
105105 source: cardData && cardData["emblem"] || "";
106− color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : Theme.palette.normal.baseText);
106+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
107107 width: height;
108108 height: source != "" ? titleLabel.font.pixelSize : 0;
109109 }
tests/plugins/Dash/cardcreator/7.res+3−3
@@ -95,7 +95,7 @@ Image {
9595 wrapMode: Text.Wrap;
9696 maximumLineCount: 2;
9797 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
98− color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : Theme.palette.normal.baseText);
98+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
9999 visible: showHeader ;
100100 text: root.title;
101101 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
@@ -113,7 +113,7 @@ Image {
113113 elide: Text.ElideRight;
114114 fontSize: "small";
115115 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
116− color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : Theme.palette.normal.baseText);
116+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
117117 visible: titleLabel.visible && titleLabel.text;
118118 text: cardData && cardData["subtitle"] || "";
119119 font.weight: Font.Light;
@@ -127,7 +127,7 @@ Image {
127127 rightMargin: units.gu(1);
128128 top: subtitleLabel.bottom;
129129 }
130− color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : Theme.palette.normal.baseText);
130+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item.luminance > 0.7 ? Theme.palette.normal.baseText : "white");
131131 model: cardData && cardData["attributes"];
132132 }
133133
tests/plugins/Dash/tst_ScopeStyle.qml+21−37
@@ -82,48 +82,32 @@ Rectangle {
8282 compare(tool.backgroundLuminance.toFixed(4), data.luminance.toFixed(4));
8383 }
8484
85− function test_threshold_data() {
85+ function test_getTextColor_data() {
8686 return [
87− { tag: "default", index: 0, threshold: 0.6824 },
88− { tag: "red on black", index: 1, threshold: 0.1063 },
89− { tag: "green on white", index: 2, threshold: 0.6795 },
90− { tag: "blue on darkgrey", index: 3, threshold: 0.3675 },
87+ { tag: "default on black", background: "black", index: 0, textColor: "white" },
88+ { tag: "default on lightgrey", background: "lightgrey", index: 0, textColor: UbuntuColors.darkGrey },
89+ { tag: "default on white", background: "white", index: 0, textColor: UbuntuColors.darkGrey },
90+ { tag: "default on yellow", background: "yellow", index: 0, textColor: UbuntuColors.darkGrey },
91+ { tag: "red/black on black", background: "black", index: 1, textColor: "red" },
92+ { tag: "red/black on lightgrey", background: "lightgrey", index: 1, textColor: "black" },
93+ { tag: "red/black on white", background: "white", index: 1, textColor: "black" },
94+ { tag: "red/black on yellow", background: "yellow", index: 1, textColor: "black" },
95+ { tag: "green/white on black", background: "black", index: 2, textColor: "white" },
96+ { tag: "green/white on lightgrey", background: "lightgrey", index: 2, textColor: "green" },
97+ { tag: "green/white on white", background: "white", index: 2, textColor: "green" },
98+ { tag: "green/white on yellow", background: "yellow", index: 2, textColor: "green" },
99+ { tag: "blue/darkgrey on black", background: "black", index: 3, textColor: "darkgrey" },
100+ { tag: "blue/darkgrey on lightgrey", background: "lightgrey", index: 3, textColor: "blue" },
101+ { tag: "blue/darkgrey on white", background: "white", index: 3, textColor: "blue" },
102+ { tag: "blue/darkgrey on yellow", background: "yellow", index: 3, textColor: "blue" },
91103 ];
92104 }
93105
94− function test_threshold(data) {
106+ function test_getTextColor(data) {
95107 tool.style = testCase.styles[data.index];
96− compare(tool.threshold.toFixed(4), data.threshold.toFixed(4), "Luminance threshold was incorrect.");
97− }
98−
99− function test_light_data() {
100− return [
101− { tag: "default", index: 0, light: "white" },
102− { tag: "red on black", index: 1, light: "red" },
103− { tag: "green on white", index: 2, light: "white" },
104− { tag: "blue on darkgrey", index: 3, light: "darkgrey" },
105− ];
106− }
107−
108− function test_light(data) {
109− tool.style = testCase.styles[data.index];
110− verify(Qt.colorEqual(tool.light, data.light),
111− "Light color not equal: %1 != %2".arg(tool.light).arg(data.light));
112− }
113−
114− function test_dark_data() {
115− return [
116− { tag: "default", index: 0, dark: UbuntuColors.darkGrey },
117− { tag: "red on black", index: 1, dark: "black" },
118− { tag: "green on white", index: 2, dark: "green" },
119− { tag: "blue on darkgrey", index: 3, dark: "blue" },
120− ];
121− }
122−
123− function test_dark(data) {
124− tool.style = testCase.styles[data.index];
125− verify(Qt.colorEqual(tool.dark, data.dark),
126− "Dark color not equal: %1 != %2".arg(tool.dark).arg(data.dark));
108+ var textColor = tool.getTextColor(Style.luminance(data.background));
109+ verify(Qt.colorEqual(textColor, data.textColor),
110+ "TextColor not equal: %1 != %2".arg(textColor).arg(data.textColor));
127111 }
128112
129113 function test_headerLogo_data() {