#!/usr/bin/python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
import cairo

def simulate_protanopia(r, g, b):
    return (0.567*r + 0.433*g, 0.558*r + 0.442*g, 0.242*g + 0.758*b)
def simulate_deuteranopia(r, g, b):
    return (0.625*r + 0.375*g, 0.7*r + 0.3*g, 0.3*g + 0.7*b)
def simulate_tritanopia(r, g, b):
    return (0.95*r + 0.05*g, 0.433*g + 0.567*b, 0.475*g + 0.525*b)

class App(Gtk.Window):
    def __init__(self):
        super().__init__(title='Color Blindness Simulator')
        self.set_default_size(520, 420)
        self.color = (0.2, 0.5, 0.9)
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
        vbox.set_margin_top(12); vbox.set_margin_bottom(12)
        vbox.set_margin_start(12); vbox.set_margin_end(12)
        self.add(vbox)
        # color chooser
        hb = Gtk.Box(spacing=10)
        hb.add(Gtk.Label(label='Pick color:'))
        self.color_btn = Gtk.ColorButton()
        rgba = Gdk.RGBA(); rgba.red=0.2; rgba.green=0.5; rgba.blue=0.9; rgba.alpha=1
        self.color_btn.set_rgba(rgba)
        self.color_btn.connect('color-set', self.update)
        hb.pack_start(self.color_btn, False, False, 0)
        vbox.pack_start(hb, False, False, 0)
        # swatches grid
        self.swatches = []
        labels = ['Original', 'Protanopia\n(Red-blind)', 'Deuteranopia\n(Green-blind)', 'Tritanopia\n(Blue-blind)']
        grid = Gtk.Grid(column_spacing=12, row_spacing=6)
        for i, lbl in enumerate(labels):
            da = Gtk.DrawingArea(); da.set_size_request(100, 80)
            da.connect('draw', self.draw_swatch, i)
            grid.attach(da, i, 0, 1, 1)
            grid.attach(Gtk.Label(label=lbl, justify=Gtk.Justification.CENTER), i, 1, 1, 1)
            self.swatches.append(da)
        vbox.pack_start(grid, True, True, 0)
        self.rgb_lbl = Gtk.Label(label='', xalign=0)
        vbox.pack_start(self.rgb_lbl, False, False, 0)
        self.update()
    def update(self, *_):
        rgba = self.color_btn.get_rgba()
        self.color = (rgba.red, rgba.green, rgba.blue)
        r,g,b = self.color
        self.rgb_lbl.set_text(f'Original: R={int(r*255)} G={int(g*255)} B={int(b*255)}  #{int(r*255):02X}{int(g*255):02X}{int(b*255):02X}')
        for da in self.swatches: da.queue_draw()
    def draw_swatch(self, w, cr, idx):
        alloc = w.get_allocation()
        r,g,b = self.color
        if idx == 0: c = (r,g,b)
        elif idx == 1: c = simulate_protanopia(r,g,b)
        elif idx == 2: c = simulate_deuteranopia(r,g,b)
        else: c = simulate_tritanopia(r,g,b)
        c = tuple(max(0,min(1,x)) for x in c)
        cr.set_source_rgb(*c); cr.paint()
        cr.set_source_rgb(0,0,0); cr.set_font_size(10)
        txt = f'#{int(c[0]*255):02X}{int(c[1]*255):02X}{int(c[2]*255):02X}'
        ext = cr.text_extents(txt)
        cr.move_to(alloc.width/2 - ext.width/2, alloc.height - 8)
        lum = 0.299*c[0]+0.587*c[1]+0.114*c[2]
        cr.set_source_rgb(0,0,0) if lum>0.5 else cr.set_source_rgb(1,1,1)
        cr.show_text(txt)

win = App()
win.connect('destroy', Gtk.main_quit)
win.show_all()
Gtk.main()
