from __future__ import absolute_import
# Copyright (c) 2010-2019 openpyxl
import re
from openpyxl.compat import safe_string, basestring
from openpyxl.descriptors import (
Descriptor,
String,
Bool,
MinMax,
Integer,
Typed,
Sequence
)
from openpyxl.descriptors.excel import HexBinary, ExtensionList
from openpyxl.descriptors.serialisable import Serialisable
# Default Color Index as per 18.8.27 of ECMA Part 4
COLOR_INDEX = (
'00000000', '00FFFFFF', '00FF0000', '0000FF00', '000000FF', #0-4
'00FFFF00', '00FF00FF', '0000FFFF', '00000000', '00FFFFFF', #5-9
'00FF0000', '0000FF00', '000000FF', '00FFFF00', '00FF00FF', #10-14
'0000FFFF', '00800000', '00008000', '00000080', '00808000', #15-19
'00800080', '00008080', '00C0C0C0', '00808080', '009999FF', #20-24
'00993366', '00FFFFCC', '00CCFFFF', '00660066', '00FF8080', #25-29
'000066CC', '00CCCCFF', '00000080', '00FF00FF', '00FFFF00', #30-34
'0000FFFF', '00800080', '00800000', '00008080', '000000FF', #35-39
'0000CCFF', '00CCFFFF', '00CCFFCC', '00FFFF99', '0099CCFF', #40-44
'00FF99CC', '00CC99FF', '00FFCC99', '003366FF', '0033CCCC', #45-49
'0099CC00', '00FFCC00', '00FF9900', '00FF6600', '00666699', #50-54
'00969696', '00003366', '00339966', '00003300', '00333300', #55-59
'00993300', '00993366', '00333399', '00333333', 'System Foreground', 'System Background' #60-64
)
# Will remove these definitions in a future release
BLACK = COLOR_INDEX[0]
WHITE = COLOR_INDEX[1]
RED = COLOR_INDEX[2]
DARKRED = COLOR_INDEX[8]
BLUE = COLOR_INDEX[4]
DARKBLUE = COLOR_INDEX[12]
GREEN = COLOR_INDEX[3]
DARKGREEN = COLOR_INDEX[9]
YELLOW = COLOR_INDEX[5]
DARKYELLOW = COLOR_INDEX[19]
aRGB_REGEX = re.compile("^([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6})$")
[docs]class RGB(Typed):
"""
Descriptor for aRGB values
If not supplied alpha is 00
"""
expected_type = basestring
def __set__(self, instance, value):
if not self.allow_none:
m = aRGB_REGEX.match(value)
if m is None:
raise ValueError("Colors must be aRGB hex values")
if len(value) == 6:
value = "00" + value
super(RGB, self).__set__(instance, value)
[docs]class Color(Serialisable):
"""Named colors for use in styles."""
tagname = "color"
rgb = RGB()
indexed = Integer()
auto = Bool()
theme = Integer()
tint = MinMax(min=-1, max=1, expected_type=float)
type = String()
def __init__(self, rgb=BLACK, indexed=None, auto=None, theme=None, tint=0.0, index=None, type='rgb'):
if index is not None:
indexed = index
if indexed is not None:
self.type = 'indexed'
self.indexed = indexed
elif theme is not None:
self.type = 'theme'
self.theme = theme
elif auto is not None:
self.type = 'auto'
self.auto = auto
else:
self.rgb = rgb
self.type = 'rgb'
self.tint = tint
@property
def value(self):
return getattr(self, self.type)
@value.setter
def value(self, value):
setattr(self, self.type, value)
def __iter__(self):
attrs = [(self.type, self.value)]
if self.tint != 0:
attrs.append(('tint', self.tint))
for k, v in attrs:
yield k, safe_string(v)
@property
def index(self):
# legacy
return self.value
def __add__(self, other):
"""
Adding colours is undefined behaviour best do nothing
"""
if not isinstance(other, Color):
return super(Color, self).__add__(other)
return self
[docs]class ColorDescriptor(Typed):
expected_type = Color
def __set__(self, instance, value):
if isinstance(value, basestring):
value = Color(rgb=value)
super(ColorDescriptor, self).__set__(instance, value)
[docs]class MRUColorList(Serialisable):
color = Sequence(expected_type=Color, )
__elements__ = ('color',)
def __init__(self,
color=None,
):
self.color = color
[docs]class RgbColor(Serialisable):
rgb = HexBinary()
def __init__(self,
rgb=None,
):
self.rgb = rgb
[docs]class IndexedColorList(Serialisable):
rgbColor = Sequence(expected_type=RgbColor, )
__elements__ = ('rgbColor',)
def __init__(self,
rgbColor=(),
):
self.rgbColor = rgbColor
[docs]class ColorList(Serialisable):
indexedColors = Typed(expected_type=IndexedColorList, allow_none=True)
mruColors = Typed(expected_type=MRUColorList, allow_none=True)
__elements__ = ('indexedColors', 'mruColors')
def __init__(self,
indexedColors=None,
mruColors=None,
):
if indexedColors is None:
indexedColors = IndexedColorList()
self.indexedColors = indexedColors
self.mruColors = mruColors
@property
def index(self):
vals = self.indexedColors.rgbColor
return [val.rgb for val in vals]