/Tools/pynche/ListViewer.py

http://unladen-swallow.googlecode.com/ · Python · 175 lines · 130 code · 12 blank · 33 comment · 20 complexity · 9588fb109ccdd9589764657876e31af6 MD5 · raw file

  1. """ListViewer class.
  2. This class implements an input/output view on the color model. It lists every
  3. unique color (e.g. unique r/g/b value) found in the color database. Each
  4. color is shown by small swatch and primary color name. Some colors have
  5. aliases -- more than one name for the same r/g/b value. These aliases are
  6. displayed in the small listbox at the bottom of the screen.
  7. Clicking on a color name or swatch selects that color and updates all other
  8. windows. When a color is selected in a different viewer, the color list is
  9. scrolled to the selected color and it is highlighted. If the selected color
  10. is an r/g/b value without a name, no scrolling occurs.
  11. You can turn off Update On Click if all you want to see is the alias for a
  12. given name, without selecting the color.
  13. """
  14. from Tkinter import *
  15. import ColorDB
  16. ADDTOVIEW = 'Color %List Window...'
  17. class ListViewer:
  18. def __init__(self, switchboard, master=None):
  19. self.__sb = switchboard
  20. optiondb = switchboard.optiondb()
  21. self.__lastbox = None
  22. self.__dontcenter = 0
  23. # GUI
  24. root = self.__root = Toplevel(master, class_='Pynche')
  25. root.protocol('WM_DELETE_WINDOW', self.withdraw)
  26. root.title('Pynche Color List')
  27. root.iconname('Pynche Color List')
  28. root.bind('<Alt-q>', self.__quit)
  29. root.bind('<Alt-Q>', self.__quit)
  30. root.bind('<Alt-w>', self.withdraw)
  31. root.bind('<Alt-W>', self.withdraw)
  32. #
  33. # create the canvas which holds everything, and its scrollbar
  34. #
  35. frame = self.__frame = Frame(root)
  36. frame.pack()
  37. canvas = self.__canvas = Canvas(frame, width=160, height=300,
  38. borderwidth=2, relief=SUNKEN)
  39. self.__scrollbar = Scrollbar(frame)
  40. self.__scrollbar.pack(fill=Y, side=RIGHT)
  41. canvas.pack(fill=BOTH, expand=1)
  42. canvas.configure(yscrollcommand=(self.__scrollbar, 'set'))
  43. self.__scrollbar.configure(command=(canvas, 'yview'))
  44. self.__populate()
  45. #
  46. # Update on click
  47. self.__uoc = BooleanVar()
  48. self.__uoc.set(optiondb.get('UPONCLICK', 1))
  49. self.__uocbtn = Checkbutton(root,
  50. text='Update on Click',
  51. variable=self.__uoc,
  52. command=self.__toggleupdate)
  53. self.__uocbtn.pack(expand=1, fill=BOTH)
  54. #
  55. # alias list
  56. self.__alabel = Label(root, text='Aliases:')
  57. self.__alabel.pack()
  58. self.__aliases = Listbox(root, height=5,
  59. selectmode=BROWSE)
  60. self.__aliases.pack(expand=1, fill=BOTH)
  61. def __populate(self):
  62. #
  63. # create all the buttons
  64. colordb = self.__sb.colordb()
  65. canvas = self.__canvas
  66. row = 0
  67. widest = 0
  68. bboxes = self.__bboxes = []
  69. for name in colordb.unique_names():
  70. exactcolor = ColorDB.triplet_to_rrggbb(colordb.find_byname(name))
  71. canvas.create_rectangle(5, row*20 + 5,
  72. 20, row*20 + 20,
  73. fill=exactcolor)
  74. textid = canvas.create_text(25, row*20 + 13,
  75. text=name,
  76. anchor=W)
  77. x1, y1, textend, y2 = canvas.bbox(textid)
  78. boxid = canvas.create_rectangle(3, row*20+3,
  79. textend+3, row*20 + 23,
  80. outline='',
  81. tags=(exactcolor, 'all'))
  82. canvas.bind('<ButtonRelease>', self.__onrelease)
  83. bboxes.append(boxid)
  84. if textend+3 > widest:
  85. widest = textend+3
  86. row += 1
  87. canvheight = (row-1)*20 + 25
  88. canvas.config(scrollregion=(0, 0, 150, canvheight))
  89. for box in bboxes:
  90. x1, y1, x2, y2 = canvas.coords(box)
  91. canvas.coords(box, x1, y1, widest, y2)
  92. def __onrelease(self, event=None):
  93. canvas = self.__canvas
  94. # find the current box
  95. x = canvas.canvasx(event.x)
  96. y = canvas.canvasy(event.y)
  97. ids = canvas.find_overlapping(x, y, x, y)
  98. for boxid in ids:
  99. if boxid in self.__bboxes:
  100. break
  101. else:
  102. ## print 'No box found!'
  103. return
  104. tags = self.__canvas.gettags(boxid)
  105. for t in tags:
  106. if t[0] == '#':
  107. break
  108. else:
  109. ## print 'No color tag found!'
  110. return
  111. red, green, blue = ColorDB.rrggbb_to_triplet(t)
  112. self.__dontcenter = 1
  113. if self.__uoc.get():
  114. self.__sb.update_views(red, green, blue)
  115. else:
  116. self.update_yourself(red, green, blue)
  117. self.__red, self.__green, self.__blue = red, green, blue
  118. def __toggleupdate(self, event=None):
  119. if self.__uoc.get():
  120. self.__sb.update_views(self.__red, self.__green, self.__blue)
  121. def __quit(self, event=None):
  122. self.__root.quit()
  123. def withdraw(self, event=None):
  124. self.__root.withdraw()
  125. def deiconify(self, event=None):
  126. self.__root.deiconify()
  127. def update_yourself(self, red, green, blue):
  128. canvas = self.__canvas
  129. # turn off the last box
  130. if self.__lastbox:
  131. canvas.itemconfigure(self.__lastbox, outline='')
  132. # turn on the current box
  133. colortag = ColorDB.triplet_to_rrggbb((red, green, blue))
  134. canvas.itemconfigure(colortag, outline='black')
  135. self.__lastbox = colortag
  136. # fill the aliases
  137. self.__aliases.delete(0, END)
  138. try:
  139. aliases = self.__sb.colordb().aliases_of(red, green, blue)[1:]
  140. except ColorDB.BadColor:
  141. self.__aliases.insert(END, '<no matching color>')
  142. return
  143. if not aliases:
  144. self.__aliases.insert(END, '<no aliases>')
  145. else:
  146. for name in aliases:
  147. self.__aliases.insert(END, name)
  148. # maybe scroll the canvas so that the item is visible
  149. if self.__dontcenter:
  150. self.__dontcenter = 0
  151. else:
  152. ig, ig, ig, y1 = canvas.coords(colortag)
  153. ig, ig, ig, y2 = canvas.coords(self.__bboxes[-1])
  154. h = int(canvas['height']) * 0.5
  155. canvas.yview('moveto', (y1-h) / y2)
  156. def save_options(self, optiondb):
  157. optiondb['UPONCLICK'] = self.__uoc.get()
  158. def colordb_changed(self, colordb):
  159. self.__canvas.delete('all')
  160. self.__populate()