Package dtk :: Package ui :: Module color_selection

Source Code for Module dtk.ui.color_selection

  1  #! /usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3   
  4  # Copyright (C) 2011 ~ 2012 Deepin, Inc. 
  5  #               2011 ~ 2012 Wang Yong 
  6  #  
  7  # Author:     Wang Yong <lazycat.manatee@gmail.com> 
  8  # Maintainer: Wang Yong <lazycat.manatee@gmail.com> 
  9  #  
 10  # This program is free software: you can redistribute it and/or modify 
 11  # it under the terms of the GNU General Public License as published by 
 12  # the Free Software Foundation, either version 3 of the License, or 
 13  # any later version. 
 14  #  
 15  # This program is distributed in the hope that it will be useful, 
 16  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 17  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 18  # GNU General Public License for more details. 
 19  #  
 20  # You should have received a copy of the GNU General Public License 
 21  # along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 22   
 23  from button import Button 
 24  from dialog import DialogBox, DIALOG_MASK_SINGLE_PAGE 
 25  from draw import draw_vlinear, draw_line, draw_pixbuf 
 26  from entry import TextEntry 
 27  from iconview import IconView 
 28  from label import Label 
 29  from locales import _ 
 30  from scrolled_window import ScrolledWindow 
 31  from spin import SpinBox 
 32  from theme import ui_theme 
 33  import gobject 
 34  import gtk 
 35  from utils import (gdkcolor_to_string, color_hex_to_cairo,  
 36                     propagate_expose, alpha_color_hex_to_cairo, 
 37                     color_hex_to_rgb, color_rgb_to_hex, cairo_disable_antialias, 
 38                     is_hex_color, place_center) 
 39   
40 -class HSV(gtk.ColorSelection):
41 ''' 42 HSV widget that use deepin-ui widget instead Gtk.ColorSelection's child widget. 43 ''' 44
45 - def __init__(self):
46 ''' 47 Initialize HSV class. 48 ''' 49 gtk.ColorSelection.__init__(self) 50 51 # Remove right buttons. 52 self.get_children()[0].remove(self.get_children()[0].get_children()[1]) 53 54 # Remove bottom color pick button. 55 self.get_children()[0].get_children()[0].remove(self.get_children()[0].get_children()[0].get_children()[1])
56
57 - def get_hsv_widget(self):
58 ''' 59 Get hsv widget in Gtk.ColorSelection widget. 60 ''' 61 return self.get_children()[0].get_children()[0].get_children()[0]
62
63 - def get_color_string(self):
64 ''' 65 Get color string. 66 ''' 67 return gdkcolor_to_string(self.get_current_color())
68
69 - def get_rgb_color(self):
70 ''' 71 Get RGB color. 72 ''' 73 gdk_color = self.get_current_color() 74 return (gdk_color.red / 256, gdk_color.green / 256, gdk_color.blue / 256)
75 76 gobject.type_register(HSV) 77
78 -class ColorSelectDialog(DialogBox):
79 ''' 80 ColorSelectionDialog widget. 81 82 @undocumented: click_confirm_button 83 @undocumented: click_cancel_button 84 @undocumented: click_rgb_spin 85 @undocumented: press_return_color_entry 86 @undocumented: expose_display_button 87 ''' 88 89 DEFAULT_COLOR_LIST = ["#000000", "#808080", "#E20417", "#F29300", "#FFEC00", "#95BE0D", "#008F35", "#00968F", "#FFFFFF", "#C0C0C0", "#E2004E", "#E2007A", "#920A7E", "#162883", "#0069B2", "#009DE0"] 90
91 - def __init__(self, 92 confirm_callback=None, 93 cancel_callback=None):
94 ''' 95 Initialize ColorSelectDialog class. 96 97 @param confirm_callback: Callback when user click OK, this callback accept one argument, color string. 98 @param cancel_callback: Callback when user click cancel, this callback don't accept any argument. 99 ''' 100 DialogBox.__init__(self, _("Select color"), mask_type=DIALOG_MASK_SINGLE_PAGE) 101 self.confirm_callback = confirm_callback 102 self.cancel_callback = cancel_callback 103 104 self.color_box = gtk.HBox() 105 self.color_align = gtk.Alignment() 106 self.color_align.set(0.5, 0.5, 0.0, 0.0) 107 self.color_align.set_padding(10, 0, 8, 8) 108 self.color_align.add(self.color_box) 109 self.color_hsv = HSV() 110 self.color_string = self.color_hsv.get_color_string() 111 (self.color_r, self.color_g, self.color_b) = self.color_hsv.get_rgb_color() 112 self.color_hsv.get_hsv_widget().connect( 113 "button-release-event", 114 lambda w, e: self.update_color_info(self.color_hsv.get_color_string())) 115 self.color_box.pack_start(self.color_hsv, False, False) 116 117 self.color_right_box = gtk.VBox() 118 self.color_right_align = gtk.Alignment() 119 self.color_right_align.set(0.5, 0.5, 0.0, 0.0) 120 self.color_right_align.set_padding(8, 0, 0, 0) 121 self.color_right_align.add(self.color_right_box) 122 self.color_box.pack_start(self.color_right_align) 123 124 self.color_info_box = gtk.HBox() 125 self.color_right_box.pack_start(self.color_info_box, False, False) 126 127 self.color_display_box = gtk.VBox() 128 self.color_display_button = gtk.Button() 129 self.color_display_button.connect("expose-event", self.expose_display_button) 130 self.color_display_button.set_size_request(70, 49) 131 self.color_display_align = gtk.Alignment() 132 self.color_display_align.set(0.5, 0.5, 1.0, 1.0) 133 self.color_display_align.set_padding(5, 5, 5, 5) 134 self.color_display_align.add(self.color_display_button) 135 self.color_display_box.pack_start(self.color_display_align, False, False, 5) 136 137 self.color_hex_box = gtk.HBox() 138 self.color_hex_label = Label(_("Color value")) 139 self.color_hex_box.pack_start(self.color_hex_label, False, False, 5) 140 self.color_hex_entry = TextEntry(self.color_string) 141 self.color_hex_entry.entry.check_text = is_hex_color 142 self.color_hex_entry.entry.connect("press-return", self.press_return_color_entry) 143 self.color_hex_entry.set_size(70, 24) 144 self.color_hex_box.pack_start(self.color_hex_entry, False, False, 5) 145 self.color_display_box.pack_start(self.color_hex_box, False, False, 5) 146 147 self.color_info_box.pack_start(self.color_display_box, False, False, 5) 148 149 self.color_rgb_box = gtk.VBox() 150 self.color_r_box = gtk.HBox() 151 self.color_r_label = Label(_("Red: ")) 152 self.color_r_spin = SpinBox(self.color_r, 0, 255, 1) 153 self.color_r_spin.connect("value-changed", lambda s, v: self.click_rgb_spin()) 154 self.color_r_box.pack_start(self.color_r_label, False, False) 155 self.color_r_box.pack_start(self.color_r_spin, False, False) 156 self.color_g_box = gtk.HBox() 157 self.color_g_label = Label(_("Green: ")) 158 self.color_g_spin = SpinBox(self.color_g, 0, 255, 1) 159 self.color_g_spin.connect("value-changed", lambda s, v: self.click_rgb_spin()) 160 self.color_g_box.pack_start(self.color_g_label, False, False) 161 self.color_g_box.pack_start(self.color_g_spin, False, False) 162 self.color_b_box = gtk.HBox() 163 self.color_b_label = Label(_("Blue: ")) 164 self.color_b_spin = SpinBox(self.color_b, 0, 255, 1) 165 self.color_b_spin.connect("value-changed", lambda s, v: self.click_rgb_spin()) 166 self.color_b_box.pack_start(self.color_b_label, False, False) 167 self.color_b_box.pack_start(self.color_b_spin, False, False) 168 169 self.color_rgb_box.pack_start(self.color_r_box, False, False, 8) 170 self.color_rgb_box.pack_start(self.color_g_box, False, False, 8) 171 self.color_rgb_box.pack_start(self.color_b_box, False, False, 8) 172 self.color_info_box.pack_start(self.color_rgb_box, False, False, 5) 173 174 self.color_select_view = IconView() 175 self.color_select_view.set_size_request(250, 60) 176 self.color_select_view.connect("button-press-item", lambda view, item, x, y: self.update_color_info(item.color, False)) 177 self.color_select_view.draw_mask = self.get_mask_func(self.color_select_view) 178 self.color_select_scrolled_window = ScrolledWindow() 179 for color in self.DEFAULT_COLOR_LIST: 180 self.color_select_view.add_items([ColorItem(color)]) 181 182 self.color_select_align = gtk.Alignment() 183 self.color_select_align.set(0.5, 0.5, 1.0, 1.0) 184 self.color_select_align.set_padding(10, 5, 6, 5) 185 186 self.color_select_scrolled_window.add_child(self.color_select_view) 187 self.color_select_scrolled_window.set_size_request(-1, 60) 188 self.color_select_align.add(self.color_select_scrolled_window) 189 self.color_right_box.pack_start(self.color_select_align, True, True) 190 191 self.confirm_button = Button(_("OK")) 192 self.cancel_button = Button(_("Cancel")) 193 194 self.confirm_button.connect("clicked", lambda w: self.click_confirm_button()) 195 self.cancel_button.connect("clicked", lambda w: self.click_cancel_button()) 196 197 self.right_button_box.set_buttons([self.confirm_button, self.cancel_button]) 198 self.body_box.pack_start(self.color_align, True, True) 199 200 self.update_color_info(self.color_string)
201
202 - def click_confirm_button(self):
203 ''' 204 Wrap callback when user click ok button. 205 ''' 206 if self.confirm_callback != None: 207 self.confirm_callback(self.color_hex_entry.get_text()) 208 209 self.destroy()
210
211 - def click_cancel_button(self):
212 ''' 213 Wrap callback when user click cancel button. 214 ''' 215 if self.cancel_callback != None: 216 self.cancel_callback() 217 218 self.destroy()
219
220 - def click_rgb_spin(self):
221 ''' 222 Callback when user click RGB spin. 223 ''' 224 self.update_color_info(color_rgb_to_hex((self.color_r_spin.get_value(), 225 self.color_g_spin.get_value(), 226 self.color_b_spin.get_value())))
227
228 - def press_return_color_entry(self, entry):
229 ''' 230 Callback when user press `return` key on entry. 231 232 @param entry: Color input entry. 233 ''' 234 self.update_color_info(entry.get_text()) 235 entry.select_all()
236
237 - def expose_display_button(self, widget, event):
238 ''' 239 Callback for `expose-event` signal. 240 241 @param widget: Gtk.Widget instance. 242 @param event: Expose event. 243 @return: Always return True 244 ''' 245 # Init. 246 cr = widget.window.cairo_create() 247 rect = widget.allocation 248 249 cr.set_source_rgb(*color_hex_to_cairo(self.color_string)) 250 cr.rectangle(rect.x, rect.y, rect.width, rect.height) 251 cr.fill() 252 253 # Propagate expose. 254 propagate_expose(widget, event) 255 256 return True
257
258 - def update_color_info(self, color_string, clear_highlight=True):
259 ''' 260 Update color information. 261 262 @param color_string: Hex color string. 263 @param clear_highlight: Whether clear color select view's highlight status, default is True. 264 ''' 265 self.color_string = color_string 266 (self.color_r, self.color_g, self.color_b) = color_hex_to_rgb(self.color_string) 267 self.color_r_spin.update(self.color_r) 268 self.color_g_spin.update(self.color_g) 269 self.color_b_spin.update(self.color_b) 270 self.color_hex_entry.set_text(self.color_string) 271 if not color_string.startswith("#"): 272 color_string = "#" + color_string 273 self.color_hsv.set_current_color(gtk.gdk.color_parse(color_string)) 274 275 if clear_highlight: 276 self.color_select_view.clear_highlight() 277 278 self.color_display_button.queue_draw()
279 280 gobject.type_register(ColorSelectDialog) 281
282 -class ColorItem(gobject.GObject):
283 ''' 284 ColorItem class for use in L{ I{ColorSelectDialog} <ColorSelectDialog>}. 285 ''' 286 287 __gsignals__ = { 288 "redraw-request" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 289 } 290
291 - def __init__(self, color):
292 ''' 293 Initialize ColorItem class. 294 295 @param color: Hex color string. 296 ''' 297 gobject.GObject.__init__(self) 298 self.color = color 299 self.width = 20 300 self.height = 16 301 self.padding_x = 4 302 self.padding_y = 4 303 self.hover_flag = False 304 self.highlight_flag = False
305
306 - def emit_redraw_request(self):
307 ''' 308 IconView interface function. 309 310 Emit `redraw-request` signal. 311 ''' 312 self.emit("redraw-request")
313
314 - def get_width(self):
315 ''' 316 IconView interface function. 317 318 Get item width. 319 @return: Return item width, in pixel. 320 ''' 321 return self.width + self.padding_x * 2
322
323 - def get_height(self):
324 ''' 325 IconView interface function. 326 327 Get item height. 328 @return: Return item height, in pixel. 329 ''' 330 return self.height + self.padding_y * 2
331
332 - def render(self, cr, rect):
333 ''' 334 IconView interface function. 335 336 Render item. 337 338 @param cr: Cairo context. 339 @param rect: Render rectangle area. 340 ''' 341 # Init. 342 draw_x = rect.x + self.padding_x 343 draw_y = rect.y + self.padding_y 344 345 # Draw color. 346 cr.set_source_rgb(*color_hex_to_cairo(self.color)) 347 cr.rectangle(draw_x, draw_y, self.width, self.height) 348 cr.fill() 349 350 if self.hover_flag: 351 cr.set_source_rgb(*color_hex_to_cairo(ui_theme.get_color("color_item_hover").get_color())) 352 cr.rectangle(draw_x, draw_y, self.width, self.height) 353 cr.stroke() 354 elif self.highlight_flag: 355 cr.set_source_rgb(*color_hex_to_cairo(ui_theme.get_color("color_item_highlight").get_color())) 356 cr.rectangle(draw_x, draw_y, self.width, self.height) 357 cr.stroke() 358 359 # Draw frame. 360 with cairo_disable_antialias(cr): 361 cr.set_line_width(1) 362 cr.set_source_rgb(*color_hex_to_cairo(ui_theme.get_color("color_item_frame").get_color())) 363 cr.rectangle(draw_x, draw_y, self.width, self.height) 364 cr.stroke()
365
366 - def icon_item_motion_notify(self, x, y):
367 ''' 368 IconView interface function. 369 370 Handle `motion-notify-event` signal. 371 372 @param x: X coordinate that user motion on item. 373 @param y: Y coordinate that user motion on item. 374 ''' 375 self.hover_flag = True 376 377 self.emit_redraw_request()
378
379 - def icon_item_lost_focus(self):
380 ''' 381 IconView interface function. 382 383 Handle `lost-focus` signal. 384 ''' 385 self.hover_flag = False 386 387 self.emit_redraw_request()
388
389 - def icon_item_highlight(self):
390 ''' 391 IconView interface function. 392 393 Handle `highlight` signal. 394 ''' 395 self.highlight_flag = True 396 397 self.emit_redraw_request()
398
399 - def icon_item_normal(self):
400 ''' 401 Normal icon item. 402 ''' 403 self.highlight_flag = False 404 405 self.emit_redraw_request()
406
407 - def icon_item_button_press(self, x, y):
408 ''' 409 IconView interface function. 410 411 Handle `button-press` signal. 412 ''' 413 pass
414
415 - def icon_item_button_release(self, x, y):
416 ''' 417 IconView interface function. 418 419 Handle `button-release` signal. 420 ''' 421 pass
422
423 - def icon_item_single_click(self, x, y):
424 ''' 425 IconView interface function. 426 427 Handle `click` signal. 428 ''' 429 pass
430
431 - def icon_item_double_click(self, x, y):
432 ''' 433 IconView interface function. 434 435 Handle `double-click` signal. 436 ''' 437 pass
438 439 gobject.type_register(ColorItem) 440
441 -class ColorButton(gtk.VBox):
442 ''' 443 Button to select color. 444 445 @undocumented: popup_color_selection_dialog 446 @undocumented: expose_button 447 @undocumented: select_color 448 ''' 449 450 __gsignals__ = { 451 "color-select" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (str,)), 452 } 453
454 - def __init__(self, color="#FF0000"):
455 ''' 456 Initialize ColorButton class. 457 458 @param color: Hex color string to initialize, default is \"#FF0000\". 459 ''' 460 gtk.VBox.__init__(self) 461 self.button = gtk.Button() 462 self.color = color 463 self.width = 69 464 self.height = 22 465 self.color_area_width = 39 466 self.color_area_height = 14 467 468 self.button.set_size_request(self.width, self.height) 469 self.pack_start(self.button, False, False) 470 471 self.button.connect("expose-event", self.expose_button) 472 self.button.connect("button-press-event", self.popup_color_selection_dialog)
473
474 - def popup_color_selection_dialog(self, widget, event):
475 ''' 476 Internal function to popup color selection dialog when user click on button. 477 478 @param widget: ColorButton widget. 479 @param event: Button press event. 480 ''' 481 dialog = ColorSelectDialog(self.select_color) 482 dialog.show_all() 483 place_center(self.get_toplevel(), dialog)
484
485 - def select_color(self, color):
486 ''' 487 Select color. 488 489 @param color: Hex color string. 490 ''' 491 self.set_color(color) 492 self.emit("color-select", color)
493
494 - def set_color(self, color):
495 ''' 496 Internal function to set color. 497 498 @param color: Hex color string. 499 ''' 500 self.color = color 501 502 self.queue_draw()
503
504 - def get_color(self):
505 ''' 506 Get color. 507 508 @return: Return hex color string. 509 ''' 510 return self.color
511
512 - def expose_button(self, widget, event):
513 ''' 514 Internal function to handle `expose-event` signal. 515 516 @param widget: ColorButton instance. 517 @param event: Expose event. 518 ''' 519 # Init. 520 cr = widget.window.cairo_create() 521 rect = widget.allocation 522 x, y, w, h = rect.x, rect.y, rect.width, rect.height 523 524 # Get color info. 525 if widget.state == gtk.STATE_NORMAL: 526 border_color = ui_theme.get_color("button_border_normal").get_color() 527 background_color = ui_theme.get_shadow_color("button_background_normal").get_color_info() 528 elif widget.state == gtk.STATE_PRELIGHT: 529 border_color = ui_theme.get_color("button_border_prelight").get_color() 530 background_color = ui_theme.get_shadow_color("button_background_prelight").get_color_info() 531 elif widget.state == gtk.STATE_ACTIVE: 532 border_color = ui_theme.get_color("button_border_active").get_color() 533 background_color = ui_theme.get_shadow_color("button_background_active").get_color_info() 534 elif widget.state == gtk.STATE_INSENSITIVE: 535 border_color = ui_theme.get_color("disable_frame").get_color() 536 disable_background_color = ui_theme.get_color("disable_background").get_color() 537 background_color = [(0, (disable_background_color, 1.0)), 538 (1, (disable_background_color, 1.0))] 539 540 # Draw background. 541 draw_vlinear( 542 cr, 543 x + 1, y + 1, w - 2, h - 2, 544 background_color) 545 546 # Draw border. 547 cr.set_source_rgb(*color_hex_to_cairo(border_color)) 548 draw_line(cr, x + 2, y + 1, x + w - 2, y + 1) # top 549 draw_line(cr, x + 2, y + h, x + w - 2, y + h) # bottom 550 draw_line(cr, x + 1, y + 2, x + 1, y + h - 2) # left 551 draw_line(cr, x + w, y + 2, x + w, y + h - 2) # right 552 553 # Draw four point. 554 if widget.state == gtk.STATE_INSENSITIVE: 555 top_left_point = ui_theme.get_pixbuf("button/disable_corner.png").get_pixbuf() 556 else: 557 top_left_point = ui_theme.get_pixbuf("button/corner.png").get_pixbuf() 558 top_right_point = top_left_point.rotate_simple(270) 559 bottom_right_point = top_left_point.rotate_simple(180) 560 bottom_left_point = top_left_point.rotate_simple(90) 561 562 draw_pixbuf(cr, top_left_point, x, y) 563 draw_pixbuf(cr, top_right_point, x + w - top_left_point.get_width(), y) 564 draw_pixbuf(cr, bottom_left_point, x, y + h - top_left_point.get_height()) 565 draw_pixbuf(cr, bottom_right_point, x + w - top_left_point.get_width(), y + h - top_left_point.get_height()) 566 567 # Draw color frame. 568 cr.set_source_rgb(*color_hex_to_cairo("#c0c0c0")) 569 cr.rectangle(x + (w - self.color_area_width) / 2, 570 y + (h - self.color_area_height) / 2, 571 self.color_area_width, 572 self.color_area_height) 573 cr.stroke() 574 575 # Draw color. 576 cr.set_source_rgb(*color_hex_to_cairo(self.color)) 577 cr.rectangle(x + (w - self.color_area_width) / 2, 578 y + (h - self.color_area_height) / 2, 579 self.color_area_width, 580 self.color_area_height) 581 cr.fill() 582 583 # Draw mask when widget is insensitive. 584 if widget.state == gtk.STATE_INSENSITIVE: 585 cr.set_source_rgba(*alpha_color_hex_to_cairo(ui_theme.get_alpha_color("color_button_disable_mask").get_color_info())) 586 cr.rectangle(x + (w - self.color_area_width) / 2, 587 y + (h - self.color_area_height) / 2, 588 self.color_area_width, 589 self.color_area_height) 590 cr.fill() 591 592 return True
593 594 gobject.type_register(ColorButton) 595