Commit 8e44939b authored by Philipp Hörist's avatar Philipp Hörist
Browse files

F17

parent c2cd53c9
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018 Jonas Wielicki <jonas AT wielicki.name>
# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of Gajim.
#
# Gajim is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Gajim is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
import math
import functools
import unicodedata
import hashlib
from gi.repository import Gdk
@functools.lru_cache()
def normalise_text_for_hash(text):
return unicodedata.normalize("NFKC", text)
def hsva_to_rgba(h, s, v, a):
if s == 0:
return v, v, v, a
h = h % (math.pi*2)
indexf = h / (math.pi*2 / 6)
index = math.floor(indexf)
fractional = indexf - index
p = v * (1.0 - s)
q = v * (1.0 - (s * fractional))
t = v * (1.0 - (s * (1.0 - fractional)))
return [
(v, t, p),
(q, v, p),
(p, v, t),
(p, q, v),
(t, p, v),
(v, p, q)
][index] + (a, )
def rgba_to_hsva(r, g, b, a):
deg_60 = math.pi / 3
Cmin = min(r, g, b)
Cmax = max(r, g, b)
delta = Cmax - Cmin
if r >= g and r >= b:
h = (g-b)/delta
elif g >= r and g >= b:
h = (b-r)/delta + 2
else:
h = (r-g)/delta + 4
h *= deg_60
if Cmax == 0:
s = 0
else:
s = delta / Cmax
return h, s, Cmax, a
def luminance(r, g, b):
return r*0.2126 + g*0.7152 + b*0.0722
def colour_distance_hsv(hsv_a, hsv_b):
h_a, s_a, v_a = hsv_a
h_b, s_b, v_b = hsv_b
r_a, g_a, b_a, _ = hsva_to_rgba(h_a, s_a, v_a, 0)
r_b, g_b, b_b, _ = hsva_to_rgba(h_b, s_b, v_b, 0)
if r_a > 0.5:
return math.sqrt(
3*(r_a-r_b)**2 +
4*(g_a-g_b)**2 +
2*(b_a-b_b)**2
)
else:
return math.sqrt(
2*(r_a-r_b)**2 +
4*(g_a-g_b)**2 +
3*(b_a-b_b)**2
)
# lum_a = luminance(r_a, g_a, b_a)
# lum_b = luminance(r_b, g_b, b_b)
# h_dist = min(abs(h_a-h_b), abs(h_b-h_a))
# return h_dist * abs(lum_a-lum_b) + abs(s_a-s_b) * abs(lum_a-lum_b)
# return abs(lum_a-lum_b)
return math.sqrt(
(r_a-r_b)**2 +
(g_a-g_b)**2 +
(b_a-b_b)**2
)
# K_R = 0.299
# K_G = 0.587
# K_R = 0.0593
# K_G = 0.2627
K_R = 0.2627
K_B = 0.0593
K_G = 1-K_R-K_B
def ycbcr_to_rgb(y, cb, cr):
r = 2*(1 - K_R)*cr + y
b = 2*(1 - K_B)*cb + y
g = (y - K_R*r - K_B*b)/K_G
return r, g, b
def clip_rgb(r, g, b):
return (
min(max(r, 0), 1),
min(max(g, 0), 1),
min(max(b, 0), 1),
)
def angle_to_cbcr_edge(angle):
cr = math.sin(angle)
cb = math.cos(angle)
# if abs(cr) > abs(cb):
# factor = 0.5 / abs(cr)
# else:
# factor = 0.5 / abs(cb)
factor = 0.5
return cb * factor, cr * factor
@functools.lru_cache()
def text_to_colour(text):
text = normalise_text_for_hash(text)
# hash_ = hashlib.sha1()
# hash_.update(text.encode("utf-8"))
# # lets take four bytes of entropy
# data = hash_.digest()
# hue, = struct.unpack("<H", data[:2])
MASK = 0xffff
# data = binascii.crc32(text.encode("utf-8"))
h = hashlib.sha1()
h.update(text.encode("utf-8"))
hue = (int.from_bytes(h.digest()[:2], "little") & MASK) / MASK
# hue = data & 0xffff
# first attempt, simply mix with the inverse of in_contrast_with
# initial_color = Qt.QColor(*struct.unpack("<BBB", data), 255)
# contrast_inverse = Qt.QColor(
# 255 - in_contrast_with[0],
# 255 - in_contrast_with[1],
# 255 - in_contrast_with[2],
# 255,
# )
# FACTOR = 0.4
# INV_FACTOR = 1-FACTOR
# return Qt.QColor(
# INV_FACTOR*initial_color.red() + FACTOR*contrast_inverse.red(),
# INV_FACTOR*initial_color.green() + FACTOR*contrast_inverse.green(),
# INV_FACTOR*initial_color.blue() + FACTOR*contrast_inverse.blue(),
# 255,
# )
# if in_contrast_with is not None:
# *back, _ = rgba_to_hsva(*in_contrast_with, 1.0)
# else:
# back = None
# while len(data) > 3:
# h, s, v = struct.unpack("<BBB", data[:3])
# data = data[1:]
# h = h/255 * math.pi*2
# s = (s//64 + 4) / 7
# v_int = (v//128 + 6)
# if back is None:
# v = v_int/7
# break
# for v_base in [v_int, v_int ^ 1]:
# v = v_base/7
# dist = colour_distance_hsv((h, s, v), back)
# if dist >= 0.4:
# break
# else:
# continue
# break
# else:
# print("out of options for", text)
# r, g, b, _ = hsva_to_rgba(h, s, v, 1)
# return r, g, b
cb, cr = angle_to_cbcr_edge(hue * math.pi * 2)
r, g, b = ycbcr_to_rgb(0.5, cb, cr)
r, g, b = clip_rgb(r, g, b)
r *= 0.8
g *= 0.8
b *= 0.8
return r, g, b
def get_color_for_jid(jid):
red, green, blue = text_to_colour(jid)
return Gdk.Color.from_floats(red, green, blue)
if __name__ == '__main__':
print(get_color_for_jid('test@test.at'))
......@@ -24,6 +24,7 @@
from gi.repository import Pango
from gajim.common import app
from gajim.common.coloring import get_color_for_jid
from gajim.common.logger import KindConstant
from gajim.common.const import Position, LineElement, LineType
......@@ -69,7 +70,7 @@ def _create_tags(self):
'pixels-below-lines': 4, 'pixels-above-lines': 8},
{'name': 'status-message', 'style': Pango.Style.ITALIC,
'pixels-below-lines': 4, 'pixels-above-lines': 8},
{'name': 'icon', 'rise': Pango.SCALE * -4},
{'name': 'icon', 'rise': Pango.SCALE * -2},
{'name': 'time', 'family': 'Monospace', 'scale': 0.8},
{'name': 'muc-subject', 'style': Pango.Style.ITALIC, 'foreground': app.config.get('statusmsgcolor')},
{'name': 'incoming', 'foreground': app.config.get('inmsgtxtcolor')},
......@@ -502,14 +503,19 @@ def _remove_line(self):
class Icons(Gtk.Box):
def __init__(self):
Gtk.Box.__init__(self)
self._encryption_image = Gtk.Image.new_from_icon_name(
'network-wireless-encrypted-symbolic', Gtk.IconSize.MENU)
icon_theme = Gtk.IconTheme.get_default()
scale = self.get_scale_factor()
print(scale)
surface = icon_theme.load_surface('network-wireless-encrypted-symbolic', 12, scale, None, Gtk.IconLookupFlags.FORCE_SIZE)
self._encryption_image = Gtk.Image.new_from_surface(surface)
self._encryption_image.set_no_show_all(True)
self._correction_image = Gtk.Image.new_from_icon_name(
'document-edit-symbolic', Gtk.IconSize.MENU)
surface = icon_theme.load_surface('document-edit-symbolic', 12, scale, None, Gtk.IconLookupFlags.FORCE_SIZE)
self._correction_image = Gtk.Image.new_from_surface(surface)
self._correction_image.set_no_show_all(True)
self._receipt_image = Gtk.Image.new_from_icon_name(
'object-select-symbolic', Gtk.IconSize.MENU)
surface = icon_theme.load_surface('object-select-symbolic', 12, scale, None, Gtk.IconLookupFlags.FORCE_SIZE)
self._receipt_image = Gtk.Image.new_from_surface(surface)
self._receipt_image.set_no_show_all(True)
self.add(self._encryption_image)
self.add(self._correction_image)
......@@ -548,6 +554,10 @@ def __init__(self, textview, type_, event):
self.nick = textview.contact.get_shown_name()
elif type_ == LineType.GC_MESSAGE:
self.nick = event.nick
if event.name == 'mam-decrypted-message-received':
self.jid = event.with_ + '/' + event.nick
else:
self.jid = event.fjid
else:
if event.name == 'message-sent':
self.nick = app.nicks[event.account]
......@@ -570,13 +580,26 @@ def _show(self):
def set_text(self, text):
_iter = self._get_iter_from_name('start-text')
if self._type_ == LineType.GC_MESSAGE:
self._buffer.insert(_iter, text)
tag = self._get_color_tag(self.jid)
self._buffer.insert_with_tags(_iter, text, tag)
else:
self._buffer.insert_with_tags_by_name(_iter, text, self.kind)
def _remove_line(self):
self.is_nickname_visible = False
def _get_color_tag(self, jid):
tag_name = '%s-color' % jid
tag = self._buffer.get_tag_table().lookup(tag_name)
if tag is not None:
return tag
color = get_color_for_jid(jid)
print(color)
tag_config = {'name': tag_name, 'foreground-gdk': color}
color_tag = Gtk.TextTag(**tag_config)
self._buffer.get_tag_table().add(color_tag)
return color_tag
class StatusMessage(TextViewLine):
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment