colorblind.py (4880B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\util\colorblind.py 2 import logging 3 from carbonui.util.color import Color 4 from clientsettings.setting import UserSettingEnum 5 from signals import Signal 6 log = logging.getLogger(__name__) 7 on_colorblind_mode_changed = Signal('on_colorblind_mode_changed') 8 RED = 0.0 9 YELLOW = 1.0 / 6 10 GREEN = 2.0 / 6 11 AQUA = 3.0 / 6 12 BLUE = 4.0 / 6 13 PINK = 5.0 / 6 14 MODE_OFF = 0 15 MODE_DEUTERANOPIA = 1 16 MODE_TRITONOPIA = 2 17 MODE_CUSTOM = 3 18 H_0 = 1.0 / 24 19 HUES = (RED, 20 YELLOW, 21 GREEN, 22 AQUA, 23 BLUE, 24 PINK) 25 HUES_BY_MODE = {MODE_DEUTERANOPIA: (YELLOW, BLUE), 26 MODE_TRITONOPIA: (RED, AQUA)} 27 28 def GetCustomHues(): 29 return settings.user.ui.Get('colorBlindCustomHues', HUES[:]) 30 31 32 def SetCustomHues(hues): 33 hues = [ hue for hue in HUES if hue in hues ] 34 return settings.user.ui.Set('colorBlindCustomHues', hues) 35 36 37 def ToggleCustomHue(hue): 38 hues = list(GetCustomHues()) 39 if hue in hues: 40 hues.remove(hue) 41 else: 42 hues.append(hue) 43 if hues: 44 SetCustomHues(hues) 45 46 47 color_replacement_setting = UserSettingEnum(settings_key='colorBlindMode', default_value=MODE_OFF, options=[MODE_OFF, 48 MODE_DEUTERANOPIA, 49 MODE_TRITONOPIA, 50 MODE_CUSTOM]) 51 52 def GetMode(): 53 return color_replacement_setting.get() 54 55 56 def SetMode(mode): 57 color_replacement_setting.set(mode) 58 59 60 def GetCurrentHues(): 61 mode = GetMode() 62 if mode == MODE_CUSTOM: 63 return GetCustomHues() 64 return HUES_BY_MODE.get(mode, []) 65 66 67 def GetReplacementColorHex(colorHex, maintainBrightness = False, maxSaturation = None): 68 col = Color.HextoRGBA(colorHex) 69 col = GetReplacementColor(col, maintainBrightness, maxSaturation) 70 return Color.RGBtoHex(*col) 71 72 73 def GetReplacementColor(color, maintainBrightness = False, maxSaturation = None): 74 try: 75 c = Color() 76 c.SetRGB(*color) 77 if not c.IsGrayscale() and c.GetBrightness() > 0.3: 78 h0, s0, b0 = c.GetHSB() 79 h, x = _GetHueAndRelativeXWithinHue(h0) 80 b, s = _GetSaturationAndBrightness(x) 81 if h == BLUE: 82 s *= 0.7 83 if maintainBrightness: 84 b = b0 85 if maxSaturation is not None: 86 s = min(maxSaturation, s) 87 c.SetHSB(h, s, b) 88 if len(color) == 4: 89 color = c.GetRGBA() 90 else: 91 color = c.GetRGB() 92 except: 93 log.exception() 94 finally: 95 return color 96 97 98 def _GetHueAndRelativeXWithinHue(hue): 99 hues = GetCurrentHues() 100 numSegments = len(hues) 101 segmentLen = 1.0 / numSegments 102 if hue <= H_0: 103 hue += 1.0 104 hue = round(hue, 3) 105 for i in xrange(numSegments): 106 hStart = round(H_0 + i * segmentLen, 3) 107 hEnd = round(hStart + segmentLen, 3) 108 if hStart <= hue and hue <= hEnd: 109 xRel = (hue - hStart) / segmentLen 110 xRel = max(0.0, min(xRel, 1.0)) 111 if i % 2: 112 xRel = 1.0 - xRel 113 try: 114 hue = hues[i + 1] 115 except IndexError: 116 hue = hues[0] 117 118 return (hue, xRel) 119 120 raise ValueError 121 122 123 def GetSaturationConstraints(): 124 SAT_MIN = 0.3 125 SAT_MAX = 1.0 126 SAT_DIFF = SAT_MAX - SAT_MIN 127 return (SAT_MIN, SAT_MAX, SAT_DIFF) 128 129 130 def GetBrightnessConstraints(): 131 BRI_MIN = 0.35 + len(GetCurrentHues()) * 0.075 132 BRI_MAX = 1.0 133 BRI_DIFF = BRI_MAX - BRI_MIN 134 return (BRI_MIN, BRI_MAX, BRI_DIFF) 135 136 137 def _GetSaturationAndBrightness(x): 138 if x > 1.0: 139 raise ValueError('x is > 1.0') 140 briMin, briMax, briDiff = GetBrightnessConstraints() 141 satMin, satMax, satDiff = GetSaturationConstraints() 142 if x <= 1.0 / 3: 143 x = 3 * x 144 s = satMin + satDiff * x 145 b = briMax 146 elif x <= 2.0 / 3: 147 x = 3 * (x - 1.0 / 3) 148 s = satMax 149 b = briMax - briDiff * x 150 else: 151 x = 3 * (x - 2.0 / 3) 152 s = satMax - satDiff * x 153 b = briMin 154 return (b, s) 155 156 157 def IsReplacementEnabled(): 158 if hasattr(session, 'charid') is False: 159 return False 160 if session.charid is None: 161 return False 162 return GetMode() != MODE_OFF 163 164 165 def CheckReplaceColor(color, maintainBrightness = False, maxSaturation = None): 166 if IsReplacementEnabled(): 167 return GetReplacementColor(color, maintainBrightness, maxSaturation) 168 return color 169 170 171 def CheckReplaceColorHex(colorHex, maintainBrightness = False, maxSaturation = None): 172 if IsReplacementEnabled(): 173 colorHex = colorHex.replace('L', '') 174 colorHex = GetReplacementColorHex(colorHex, maintainBrightness, maxSaturation) 175 return colorHex 176 177 178 def GetEvenlyDistributedColor(color, i, numColors): 179 x = H_0 + float(i) / numColors 180 if x >= 1.0: 181 x -= 1.0 182 color = Color(*color) 183 if not color.IsGrayscale(): 184 color.SetHSB(x, 1.0, 1.0) 185 return color.GetRGBA()