1"""Chip viewer and widget.
2
3In the lower left corner of the main Pynche window, you will see two
4ChipWidgets, one for the selected color and one for the nearest color.  The
5selected color is the actual RGB value expressed as an X11 #COLOR name. The
6nearest color is the named color from the X11 database that is closest to the
7selected color in 3D space.  There may be other colors equally close, but the
8nearest one is the first one found.
9
10Clicking on the nearest color chip selects that named color.
11
12The ChipViewer class includes the entire lower left quandrant; i.e. both the
13selected and nearest ChipWidgets.
14"""
15
16from Tkinter import *
17import ColorDB
18
19
20class ChipWidget:
21    _WIDTH = 150
22    _HEIGHT = 80
23
24    def __init__(self,
25                 master = None,
26                 width  = _WIDTH,
27                 height = _HEIGHT,
28                 text   = 'Color',
29                 initialcolor = 'blue',
30                 presscmd   = None,
31                 releasecmd = None):
32        # create the text label
33        self.__label = Label(master, text=text)
34        self.__label.grid(row=0, column=0)
35        # create the color chip, implemented as a frame
36        self.__chip = Frame(master, relief=RAISED, borderwidth=2,
37                            width=width,
38                            height=height,
39                            background=initialcolor)
40        self.__chip.grid(row=1, column=0)
41        # create the color name
42        self.__namevar = StringVar()
43        self.__namevar.set(initialcolor)
44        self.__name = Entry(master, textvariable=self.__namevar,
45                            relief=FLAT, justify=CENTER, state=DISABLED,
46                            font=self.__label['font'])
47        self.__name.grid(row=2, column=0)
48        # create the message area
49        self.__msgvar = StringVar()
50        self.__name = Entry(master, textvariable=self.__msgvar,
51                            relief=FLAT, justify=CENTER, state=DISABLED,
52                            font=self.__label['font'])
53        self.__name.grid(row=3, column=0)
54        # set bindings
55        if presscmd:
56            self.__chip.bind('<ButtonPress-1>', presscmd)
57        if releasecmd:
58            self.__chip.bind('<ButtonRelease-1>', releasecmd)
59
60    def set_color(self, color):
61        self.__chip.config(background=color)
62
63    def get_color(self):
64        return self.__chip['background']
65
66    def set_name(self, colorname):
67        self.__namevar.set(colorname)
68
69    def set_message(self, message):
70        self.__msgvar.set(message)
71
72    def press(self):
73        self.__chip.configure(relief=SUNKEN)
74
75    def release(self):
76        self.__chip.configure(relief=RAISED)
77
78
79
80class ChipViewer:
81    def __init__(self, switchboard, master=None):
82        self.__sb = switchboard
83        self.__frame = Frame(master, relief=RAISED, borderwidth=1)
84        self.__frame.grid(row=3, column=0, ipadx=5, sticky='NSEW')
85        # create the chip that will display the currently selected color
86        # exactly
87        self.__sframe = Frame(self.__frame)
88        self.__sframe.grid(row=0, column=0)
89        self.__selected = ChipWidget(self.__sframe, text='Selected')
90        # create the chip that will display the nearest real X11 color
91        # database color name
92        self.__nframe = Frame(self.__frame)
93        self.__nframe.grid(row=0, column=1)
94        self.__nearest = ChipWidget(self.__nframe, text='Nearest',
95                                    presscmd = self.__buttonpress,
96                                    releasecmd = self.__buttonrelease)
97
98    def update_yourself(self, red, green, blue):
99        # Selected always shows the #rrggbb name of the color, nearest always
100        # shows the name of the nearest color in the database.  BAW: should
101        # an exact match be indicated in some way?
102        #
103        # Always use the #rrggbb style to actually set the color, since we may
104        # not be using X color names (e.g. "web-safe" names)
105        colordb = self.__sb.colordb()
106        rgbtuple = (red, green, blue)
107        rrggbb = ColorDB.triplet_to_rrggbb(rgbtuple)
108        # find the nearest
109        nearest = colordb.nearest(red, green, blue)
110        nearest_tuple = colordb.find_byname(nearest)
111        nearest_rrggbb = ColorDB.triplet_to_rrggbb(nearest_tuple)
112        self.__selected.set_color(rrggbb)
113        self.__nearest.set_color(nearest_rrggbb)
114        # set the name and messages areas
115        self.__selected.set_name(rrggbb)
116        if rrggbb == nearest_rrggbb:
117            self.__selected.set_message(nearest)
118        else:
119            self.__selected.set_message('')
120        self.__nearest.set_name(nearest_rrggbb)
121        self.__nearest.set_message(nearest)
122
123    def __buttonpress(self, event=None):
124        self.__nearest.press()
125
126    def __buttonrelease(self, event=None):
127        self.__nearest.release()
128        rrggbb = self.__nearest.get_color()
129        red, green, blue = ColorDB.rrggbb_to_triplet(rrggbb)
130        self.__sb.update_views(red, green, blue)
131