blob: b4b5ad74029cb96a08bec74b2fec0cd48f8e1d87 [file] [log] [blame]
Barry Warsawfefbf791998-01-31 23:39:01 +00001"""Main Pynche (Pythonically Natural Color and Hue Editor) widget.
2"""
3
4from Tkinter import *
5import Pmw
6import ColorDB
7from ChipWidget import ChipWidget
Barry Warsawa6f591a1998-02-11 17:19:54 +00008from TypeinWidget import TypeinWidget
Barry Warsaw29fe4dd1998-02-12 19:52:31 +00009from StripWidget import StripWidget
Barry Warsawa114eb51998-03-16 23:08:35 +000010from OptionsWidget import PyncheOptions
Barry Warsawfefbf791998-01-31 23:39:01 +000011
Barry Warsaw552ac171998-02-17 22:25:23 +000012
13
14ABOUTTEXT = '''Pynche 1.0 -- The Pythonically Natural Color and Hue Editor
15Copyright (C) 1998 Barry A. Warsaw
16
17Pynche is based on ICE 1.2 (Interactive Color Editor), written by
18Barry A. Warsaw for the SunView window system in 1987.'''
19
20
Barry Warsaw29fe4dd1998-02-12 19:52:31 +000021
22def constant(numchips):
23 step = 255.0 / (numchips - 1)
24 start = 0.0
25 seq = []
26 while numchips > 0:
27 seq.append(int(start))
28 start = start + step
29 numchips = numchips - 1
30 return seq
31
Barry Warsaw79a78791998-02-13 21:28:14 +000032# red variations, green+blue = cyan constant
33def constant_cyan_generator(numchips, rgbtuple):
34 red, green, blue = rgbtuple
Barry Warsaw29fe4dd1998-02-12 19:52:31 +000035 seq = constant(numchips)
Barry Warsaw79a78791998-02-13 21:28:14 +000036 return map(None, seq, [green] * numchips, [blue] * numchips)
Barry Warsaw29fe4dd1998-02-12 19:52:31 +000037
Barry Warsaw79a78791998-02-13 21:28:14 +000038# green variations, red+blue = magenta constant
39def constant_magenta_generator(numchips, rgbtuple):
40 red, green, blue = rgbtuple
Barry Warsaw29fe4dd1998-02-12 19:52:31 +000041 seq = constant(numchips)
Barry Warsaw79a78791998-02-13 21:28:14 +000042 return map(None, [red] * numchips, seq, [blue] * numchips)
Barry Warsaw29fe4dd1998-02-12 19:52:31 +000043
Barry Warsaw79a78791998-02-13 21:28:14 +000044# blue variations, red+green = yellow constant
45def constant_yellow_generator(numchips, rgbtuple):
46 red, green, blue = rgbtuple
Barry Warsaw29fe4dd1998-02-12 19:52:31 +000047 seq = constant(numchips)
Barry Warsaw79a78791998-02-13 21:28:14 +000048 return map(None, [red] * numchips, [green] * numchips, seq)
Barry Warsaw29fe4dd1998-02-12 19:52:31 +000049
50
51
Barry Warsawfefbf791998-01-31 23:39:01 +000052class PyncheWidget(Pmw.MegaWidget):
53 def __init__(self, colordb, parent=None, **kw):
54 self.__colordb = colordb
Barry Warsaw552ac171998-02-17 22:25:23 +000055 self.__parent = parent
Barry Warsawf67575d1998-03-10 00:17:01 +000056 self.__about_dialog = None
57 self.__options_dialog = None
Barry Warsawfefbf791998-01-31 23:39:01 +000058
Barry Warsawa6f591a1998-02-11 17:19:54 +000059 options = (('color', (128, 128, 128), self.__set_color),
60 ('delegate', None, None),
61 )
62 self.defineoptions(kw, options)
Barry Warsawfefbf791998-01-31 23:39:01 +000063
64 # initialize base class -- after defining options
65 Pmw.MegaWidget.__init__(self, parent)
Barry Warsaw552ac171998-02-17 22:25:23 +000066
67 # create menubar
68 self.__menubar = Pmw.MenuBar(parent,
69 hull_relief=RAISED,
70 hull_borderwidth=1)
71 self.__menubar.pack(side=TOP, expand=YES, fill=BOTH)
72 self.__menubar.addmenu('File', None)
73 self.__menubar.addmenuitem('File',
74 type=COMMAND,
75 label='Quit',
76 command=self.__quit,
77 accelerator='Alt-Q')
Barry Warsawf67575d1998-03-10 00:17:01 +000078 parent.bind('<Alt-q>', self.__quit)
79 parent.bind('<Alt-Q>', self.__quit)
80
Barry Warsaw552ac171998-02-17 22:25:23 +000081 self.__menubar.addmenu('Help', None, side=RIGHT)
82 self.__menubar.addmenuitem('Help',
83 type=COMMAND,
84 label='About...',
85 command=self.__popup_about,
86 accelerator='Alt-A')
Barry Warsaw552ac171998-02-17 22:25:23 +000087 parent.bind('<Alt-a>', self.__popup_about)
88 parent.bind('<Alt-A>', self.__popup_about)
Barry Warsawfefbf791998-01-31 23:39:01 +000089
Barry Warsawf67575d1998-03-10 00:17:01 +000090 self.__menubar.addmenu('Edit', None)
91 self.__menubar.addmenuitem('Edit',
92 type=COMMAND,
93 label='Options...',
94 command=self.__popup_options,
95 accelerator='Alt-O')
96 parent.bind('<Alt-o>', self.__popup_options)
97 parent.bind('<Alt-O>', self.__popup_options)
98
Barry Warsawfefbf791998-01-31 23:39:01 +000099 # create color selectors
Barry Warsaw93737b21998-02-17 03:09:19 +0000100 group = Pmw.Group(parent, tag_text='Variations')
Barry Warsaw29fe4dd1998-02-12 19:52:31 +0000101 group.pack(side=TOP, expand=YES, fill=BOTH)
102 self.__reds = StripWidget(group.interior(),
Barry Warsaw79a78791998-02-13 21:28:14 +0000103 generator=constant_cyan_generator,
Barry Warsaw93737b21998-02-17 03:09:19 +0000104 axis=0, label='Red Variations')
Barry Warsaw29fe4dd1998-02-12 19:52:31 +0000105 self.__reds.pack()
106 self.__blues = StripWidget(group.interior(),
Barry Warsaw79a78791998-02-13 21:28:14 +0000107 generator=constant_magenta_generator,
Barry Warsaw93737b21998-02-17 03:09:19 +0000108 axis=1, label='Green Variations')
Barry Warsaw29fe4dd1998-02-12 19:52:31 +0000109 self.__blues.pack()
110 self.__greens = StripWidget(group.interior(),
Barry Warsaw79a78791998-02-13 21:28:14 +0000111 generator=constant_yellow_generator,
Barry Warsaw93737b21998-02-17 03:09:19 +0000112 axis=2, label='Blue Variations')
Barry Warsaw29fe4dd1998-02-12 19:52:31 +0000113 self.__greens.pack()
Barry Warsawfefbf791998-01-31 23:39:01 +0000114
115 # create chip window
116 group = Pmw.Group(parent, tag_text='Current Color')
Barry Warsawa114eb51998-03-16 23:08:35 +0000117 interior = group.interior()
Barry Warsaw93737b21998-02-17 03:09:19 +0000118 group.pack(side=LEFT, expand=YES, fill=BOTH)
Barry Warsawa114eb51998-03-16 23:08:35 +0000119 self.__selected = ChipWidget(interior,
Barry Warsawfefbf791998-01-31 23:39:01 +0000120 label_text='Selected')
121 self.__selected.grid()
Barry Warsawa114eb51998-03-16 23:08:35 +0000122 self.__nearest = ChipWidget(interior,
Barry Warsawfefbf791998-01-31 23:39:01 +0000123 label_text='Nearest')
124 self.__nearest.grid(row=0, column=1)
Barry Warsaw552ac171998-02-17 22:25:23 +0000125
126 # TBD: this is somewhat bogus, as the code should be in a derived
127 # class of ChipWidget.
128 self.__chip = self.__nearest.component('chip')
129 self.__chip.bind('<ButtonPress-1>', self.__buttonpress)
130 self.__chip.bind('<ButtonRelease-1>', self.__buttonrelease)
Barry Warsawfefbf791998-01-31 23:39:01 +0000131
Barry Warsawa114eb51998-03-16 23:08:35 +0000132 # create the type-in window
133 self.__typein = TypeinWidget(interior)
Barry Warsaw93737b21998-02-17 03:09:19 +0000134 self.__typein.grid(row=0, column=2)
Barry Warsawfefbf791998-01-31 23:39:01 +0000135
Barry Warsawa114eb51998-03-16 23:08:35 +0000136 # create the type-in color name field
137## self.__colorname = self.createcomponent(
138## 'colorname', (), None,
139## Pmw.EntryField, (interior,),
140## label_text='Color Name'
141## )
142## self.__colorname.pack()
143## self.__colorname.configure(command=self.__set_color_by_name())
144
Barry Warsawfefbf791998-01-31 23:39:01 +0000145 # Check keywords and initialize options
146 self.initialiseoptions(PyncheWidget)
147
Barry Warsawa6f591a1998-02-11 17:19:54 +0000148 self.__typein.configure(delegate=self)
Barry Warsaw93737b21998-02-17 03:09:19 +0000149 self.__reds.configure(delegate=self)
150 self.__greens.configure(delegate=self)
151 self.__blues.configure(delegate=self)
Barry Warsawa6f591a1998-02-11 17:19:54 +0000152
153 #
154 # PUBLIC INTERFACE
155 #
156
157
158 def set_color(self, obj, rgbtuple):
Barry Warsawa6f591a1998-02-11 17:19:54 +0000159 nearest = self.__colordb.nearest(rgbtuple)
Barry Warsaw55d3ffa1998-02-11 18:55:50 +0000160 red, green, blue = self.__colordb.find_byname(nearest)
Barry Warsawa6f591a1998-02-11 17:19:54 +0000161 # for an exact match, use the color name
162 if (red, green, blue) == rgbtuple:
163 self.__selected.configure(color=nearest)
164 # otherwise, use the #rrggbb name
165 else:
166 rrggbb = ColorDB.triplet_to_rrggbb(rgbtuple)
167 self.__selected.configure(color=rrggbb)
Barry Warsaw29fe4dd1998-02-12 19:52:31 +0000168
169 # configure all subwidgets
Barry Warsawa6f591a1998-02-11 17:19:54 +0000170 self.__nearest.configure(color=nearest)
171 self.__typein.configure(color=rgbtuple)
Barry Warsaw29fe4dd1998-02-12 19:52:31 +0000172 self.__reds.configure(color=rgbtuple)
173 self.__greens.configure(color=rgbtuple)
174 self.__blues.configure(color=rgbtuple)
Barry Warsawa6f591a1998-02-11 17:19:54 +0000175 delegate = self['delegate']
176 if delegate:
177 delegate.set_color(self, rgbtuple)
178
179 #
180 # PRIVATE INTERFACE
181 #
Barry Warsawfefbf791998-01-31 23:39:01 +0000182
183 def __set_color(self):
Barry Warsawa6f591a1998-02-11 17:19:54 +0000184 self.set_color(self, self['color'])
Barry Warsaw93737b21998-02-17 03:09:19 +0000185
Barry Warsawa114eb51998-03-16 23:08:35 +0000186 def __set_color_by_name(self):
187 colorname = self.__colorname.get()
188 rgbtuple = self.__colordb.find_byname(colorname)
189 self.set_color(self, rgbtuple)
190
Barry Warsaw552ac171998-02-17 22:25:23 +0000191 def __buttonpress(self, event=None):
192 self.__chip.configure(relief=SUNKEN)
193
194 def __buttonrelease(self, event=None):
195 self.__chip.configure(relief=RAISED)
Barry Warsaw93737b21998-02-17 03:09:19 +0000196 color = self.__nearest['color']
197 rgbtuple = self.__colordb.find_byname(color)
198 self.set_color(self, rgbtuple)
Barry Warsaw552ac171998-02-17 22:25:23 +0000199
200 def __quit(self, event=None):
201 self.__parent.quit()
202
203 def __popup_about(self, event=None):
Barry Warsawf67575d1998-03-10 00:17:01 +0000204 if not self.__about_dialog:
Barry Warsaw552ac171998-02-17 22:25:23 +0000205 Pmw.aboutversion('1.0')
206 Pmw.aboutcopyright('Copyright (C) 1998 Barry A. Warsaw\n'
207 'All rights reserved')
208 Pmw.aboutcontact('For information about Pynche contact:\n'
209 'Barry A. Warsaw\n'
210 'email: bwarsaw@python.org')
Barry Warsawf67575d1998-03-10 00:17:01 +0000211 self.__about_dialog = Pmw.AboutDialog(
Barry Warsaw552ac171998-02-17 22:25:23 +0000212 applicationname='Pynche -- the PYthonically Natural\n'
213 'Color and Hue Editor')
Barry Warsawf67575d1998-03-10 00:17:01 +0000214 self.__about_dialog.show()
215
216 def __popup_options(self, event=None):
217 if not self.__options_dialog:
Barry Warsawa114eb51998-03-16 23:08:35 +0000218 self.__options_dialog = PyncheOptions(
219 title='Pynche Options',
220 applycommand=self.__apply)
221 # pop up the window, non-modal
222 self.__options_dialog.deiconify()
223
224 def __apply(self):
Barry Warsawf67575d1998-03-10 00:17:01 +0000225 self.__typein.set_update_on_typing(
226 self.__options_dialog.get_value('typing'))
Barry Warsawa114eb51998-03-16 23:08:35 +0000227 flag = self.__options_dialog.get_value('dragging')
228 for strip in (self.__reds, self.__greens, self.__blues):
229 strip.set_update_while_dragging(flag)