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 import qutebrowser.utils.message as message
from qutebrowser.utils.log import downloads as logger from qutebrowser.utils.log import downloads as logger
from qutebrowser.utils.usertypes import PromptMode from qutebrowser.utils.usertypes import PromptMode
from qutebrowser.utils.misc import interpolate_color
class DownloadItem(QObject): class DownloadItem(QObject):
@ -111,6 +112,16 @@ class DownloadItem(QObject):
else: else:
return 100 * self.bytes_done / self.bytes_total 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): def cancel(self):
"""Cancel the download.""" """Cancel the download."""
logger.debug("cancelled") logger.debug("cancelled")

View File

@ -894,6 +894,22 @@ DATA = OrderedDict([
'left bottom, color-stop(0%,#FFF785), ' 'left bottom, color-stop(0%,#FFF785), '
'color-stop(100%,#FFC542))'), 'color-stop(100%,#FFC542))'),
"Background color for hints."), "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( ('fonts', sect.KeyValue(

View File

@ -434,6 +434,42 @@ class Command(BaseType):
return out 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): class CssColor(BaseType):
"""Base class for a CSS color value.""" """Base class for a CSS color value."""

View File

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

View File

@ -30,6 +30,7 @@ from tempfile import mkdtemp
from unittest import TestCase from unittest import TestCase
from PyQt5.QtCore import QStandardPaths, QCoreApplication from PyQt5.QtCore import QStandardPaths, QCoreApplication
from PyQt5.QtGui import QColor
import qutebrowser.utils.misc as utils import qutebrowser.utils.misc as utils
from qutebrowser.test.helpers import environ_set_temp 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]]) 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__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -33,6 +33,7 @@ from functools import reduce
from distutils.version import StrictVersion as Version from distutils.version import StrictVersion as Version
from PyQt5.QtCore import QCoreApplication, QStandardPaths, qVersion from PyQt5.QtCore import QCoreApplication, QStandardPaths, qVersion
from PyQt5.QtGui import QColor
from pkg_resources import resource_string from pkg_resources import resource_string
import qutebrowser import qutebrowser
@ -285,3 +286,71 @@ def get_qt_args(namespace):
argv.append('-' + argname) argv.append('-' + argname)
argv.append(val[0]) argv.append(val[0])
return argv 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())