Add colors to DownloadView

This commit is contained in:
Florian Bruhin 2014-06-12 21:43:30 +02:00
parent 3c2c08f73a
commit 2ffc9bb00a
6 changed files with 236 additions and 6 deletions

View File

@ -26,6 +26,7 @@ import qutebrowser.config.config as config
import qutebrowser.utils.message as message
from qutebrowser.utils.log import downloads as logger
from qutebrowser.utils.usertypes import PromptMode
from qutebrowser.utils.misc import interpolate_color
class DownloadItem(QObject):
@ -111,6 +112,16 @@ class DownloadItem(QObject):
else:
return 100 * self.bytes_done / self.bytes_total
def bg_color(self):
"""Background color to be shown."""
start = config.get('colors', 'download.bg.start')
stop = config.get('colors', 'download.bg.stop')
system = config.get('colors', 'download.bg.system')
if self.percentage is None:
return start
else:
return interpolate_color(start, stop, self.percentage, system)
def cancel(self):
"""Cancel the download."""
logger.debug("cancelled")

View File

@ -894,6 +894,22 @@ DATA = OrderedDict([
'left bottom, color-stop(0%,#FFF785), '
'color-stop(100%,#FFC542))'),
"Background color for hints."),
('download.fg',
SettingValue(types.QtColor(), '#ffffff'),
"Foreground color for downloads."),
('download.bg.start',
SettingValue(types.QtColor(), '#0000aa'),
"Color gradient start for downloads."),
('download.bg.stop',
SettingValue(types.QtColor(), '#00aa00'),
"Color gradient end for downloads."),
('download.bg.system',
SettingValue(types.ColorSystem(), 'rgb'),
"Color gradient interpolation system for downloads."),
)),
('fonts', sect.KeyValue(

View File

@ -434,6 +434,42 @@ class Command(BaseType):
return out
class ColorSystem(BaseType):
"""Color systems for interpolation."""
valid_values = ValidValues(('rgb', "Interpolate in the RGB color system."),
('hsv', "Interpolate in the HSV color system."),
('hsl', "Interpolate in the HSV color system."))
def validate(self, value):
super().validate(value.lower())
def transform(self, value):
mapping = {
'rgb': QColor.Rgb,
'hsv': QColor.Hsv,
'hsl': QColor.Hsl,
}
return mapping[value.lower()]
class QtColor(BaseType):
"""Base class for QColor."""
typestr = 'qcolor'
def validate(self, value):
if QColor.isValidColor(value):
pass
else:
raise ValidationError(value, "must be a valid color")
def transform(self, value):
return QColor(value)
class CssColor(BaseType):
"""Base class for a CSS color value."""

View File

@ -21,6 +21,8 @@ from PyQt5.QtCore import (pyqtSlot, Qt, QVariant, QAbstractListModel,
QModelIndex)
from PyQt5.QtWidgets import QApplication
import qutebrowser.config.config as config
class DownloadModel(QAbstractListModel):
@ -59,19 +61,26 @@ class DownloadModel(QAbstractListModel):
"""Download data from DownloadManager."""
if not index.isValid():
return QVariant()
elif role != Qt.DisplayRole:
return QVariant()
elif index.parent().isValid() or index.column() != 0:
return QVariant()
try:
item = self.downloadmanager.downloads[index.row()]
except IndexError:
return QVariant()
if role == Qt.DisplayRole:
perc = item.percentage
if perc is None:
return QVariant()
data = QVariant()
else:
return str(round(perc)) # FIXME
data = str(round(perc)) # FIXME
elif role == Qt.ForegroundRole:
data = config.get('colors', 'download.fg')
elif role == Qt.BackgroundRole:
data = item.bg_color()
else:
data = QVariant()
return data
def rowCount(self, parent):
"""Get count of active downloads."""

View File

@ -30,6 +30,7 @@ from tempfile import mkdtemp
from unittest import TestCase
from PyQt5.QtCore import QStandardPaths, QCoreApplication
from PyQt5.QtGui import QColor
import qutebrowser.utils.misc as utils
from qutebrowser.test.helpers import environ_set_temp
@ -436,5 +437,93 @@ class GetQtArgsTests(TestCase):
self.assertEqual(utils.get_qt_args(ns), [sys.argv[0]])
class InterpolateColorTests(TestCase):
"""Tests for interpolate_color.
Attributes:
white: The QColor white as a valid QColor for tests.
white: The QColor black as a valid QColor for tests.
"""
def setUp(self):
self.white = QColor('white')
self.black = QColor('black')
def test_invalid_start(self):
"""Test an invalid start color."""
with self.assertRaises(ValueError):
utils.interpolate_color(QColor(), self.white, 0)
def test_invalid_end(self):
"""Test an invalid end color."""
with self.assertRaises(ValueError):
utils.interpolate_color(self.white, QColor(), 0)
def test_invalid_percentage(self):
"""Test an invalid percentage."""
with self.assertRaises(ValueError):
utils.interpolate_color(self.white, self.white, -1)
with self.assertRaises(ValueError):
utils.interpolate_color(self.white, self.white, 101)
def test_invalid_colorspace(self):
"""Test an invalid colorspace."""
with self.assertRaises(ValueError):
utils.interpolate_color(self.white, self.black, 10, QColor.Cmyk)
def test_valid_percentages_rgb(self):
"""Test 0% and 100% in the RGB colorspace."""
white = utils.interpolate_color(self.white, self.black, 0, QColor.Rgb)
black = utils.interpolate_color(self.white, self.black, 100,
QColor.Rgb)
self.assertEqual(white, self.white)
self.assertEqual(black, self.black)
def test_valid_percentages_hsv(self):
"""Test 0% and 100% in the HSV colorspace."""
white = utils.interpolate_color(self.white, self.black, 0, QColor.Hsv)
black = utils.interpolate_color(self.white, self.black, 100,
QColor.Hsv)
self.assertEqual(white, self.white)
self.assertEqual(black, self.black)
def test_valid_percentages_hsl(self):
"""Test 0% and 100% in the HSL colorspace."""
white = utils.interpolate_color(self.white, self.black, 0, QColor.Hsl)
black = utils.interpolate_color(self.white, self.black, 100,
QColor.Hsl)
self.assertEqual(white, self.white)
self.assertEqual(black, self.black)
def test_interpolation_rgb(self):
"""Test an interpolation in the RGB colorspace."""
color = utils.interpolate_color(QColor(0, 40, 100), QColor(0, 20, 200),
50, QColor.Rgb)
self.assertEqual(color, QColor(0, 30, 150))
def test_interpolation_hsv(self):
"""Test an interpolation in the HSV colorspace."""
start = QColor()
stop = QColor()
start.setHsv(0, 40, 100)
stop.setHsv(0, 20, 200)
color = utils.interpolate_color(start, stop, 50, QColor.Hsv)
expected = QColor()
expected.setHsv(0, 30, 150)
self.assertEqual(color, expected)
def test_interpolation_hsl(self):
"""Test an interpolation in the HSL colorspace."""
start = QColor()
stop = QColor()
start.setHsl(0, 40, 100)
stop.setHsl(0, 20, 200)
color = utils.interpolate_color(start, stop, 50, QColor.Hsl)
expected = QColor()
expected.setHsl(0, 30, 150)
self.assertEqual(color, expected)
if __name__ == '__main__':
unittest.main()

View File

@ -33,6 +33,7 @@ from functools import reduce
from distutils.version import StrictVersion as Version
from PyQt5.QtCore import QCoreApplication, QStandardPaths, qVersion
from PyQt5.QtGui import QColor
from pkg_resources import resource_string
import qutebrowser
@ -285,3 +286,71 @@ def get_qt_args(namespace):
argv.append('-' + argname)
argv.append(val[0])
return argv
def _get_color_percentage(a_c1, a_c2, a_c3, b_c1, b_c2, b_c3, percent):
"""Get a color which is percent% interpolated between start and end.
Args:
a_c1, a_c2, a_c3: Start color components (R, G, B / H, S, V / H, S, L)
b_c1, b_c2, b_c3: End color components (R, G, B / H, S, V / H, S, L)
percent: Percentage to interpolate, 0-100.
0: Start color will be returned.
100: End color will be returned.
Return:
A (c1, c2, c3) tuple with the interpolated color components.
Raise:
ValueError if the percentage was invalid.
"""
if not 0 <= percent <= 100:
raise ValueError("percent needs to be between 0 and 100!")
out_c1 = round(a_c1 + (b_c1 - a_c1) * percent / 100)
out_c2 = round(a_c2 + (b_c2 - a_c2) * percent / 100)
out_c3 = round(a_c3 + (b_c3 - a_c3) * percent / 100)
return (out_c1, out_c2, out_c3)
def interpolate_color(start, end, percent, colorspace=QColor.Rgb):
"""Get an interpolated color value.
Args:
start: The start color.
end: The end color.
percent: Which value to get (0 - 100)
colorspace: The desired interpolation colorsystem,
QColor::{Rgb,Hsv,Hsl} (from QColor::Spec enum)
Return:
The interpolated QColor, with the same spec as the given start color.
Raise:
ValueError if invalid parameters are passed.
"""
if not start.isValid():
raise ValueError("Invalid start color")
if not end.isValid():
raise ValueError("Invalid end color")
out = QColor()
if colorspace == QColor.Rgb:
a_c1, a_c2, a_c3, _alpha = start.getRgb()
b_c1, b_c2, b_c3, _alpha = end.getRgb()
components = _get_color_percentage(a_c1, a_c2, a_c3, b_c1, b_c2, b_c3,
percent)
out.setRgb(*components)
elif colorspace == QColor.Hsv:
a_c1, a_c2, a_c3, _alpha = start.getHsv()
b_c1, b_c2, b_c3, _alpha = end.getHsv()
components = _get_color_percentage(a_c1, a_c2, a_c3, b_c1, b_c2, b_c3,
percent)
out.setHsv(*components)
elif colorspace == QColor.Hsl:
a_c1, a_c2, a_c3, _alpha = start.getHsl()
b_c1, b_c2, b_c3, _alpha = end.getHsl()
components = _get_color_percentage(a_c1, a_c2, a_c3, b_c1, b_c2, b_c3,
percent)
out.setHsl(*components)
else:
raise ValueError("Invalid colorspace!")
return out.convertTo(start.spec())