Package dtk :: Package ui :: Module droplist

Source Code for Module dtk.ui.droplist

  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 constant import DEFAULT_FONT_SIZE, ALIGN_START, ALIGN_MIDDLE, WIDGET_POS_TOP_LEFT 
 24  from draw import draw_vlinear, draw_text 
 25  from keymap import get_keyevent_name 
 26  from line import HSeparator 
 27  from scrolled_window import ScrolledWindow 
 28  from theme import ui_theme 
 29  import gobject 
 30  import gtk 
 31  from utils import (is_in_rect, get_content_size, propagate_expose,  
 32                     get_widget_root_coordinate, get_screen_size,  
 33                     alpha_color_hex_to_cairo,  
 34                     cairo_disable_antialias, color_hex_to_cairo) 
 35   
 36  __all__ = ["DroplistScrolledWindow", "Droplist", "DroplistItem"] 
 37   
 38  droplist_grab_window = gtk.Window(gtk.WINDOW_POPUP) 
 39  droplist_grab_window.move(0, 0) 
 40  droplist_grab_window.set_default_size(0, 0) 
 41  droplist_grab_window.show() 
 42  droplist_active_item = None 
 43  droplist_grab_window_press_flag = False 
 44   
 45  root_droplists = [] 
 46   
47 -def droplist_grab_window_focus_in():
48 ''' 49 Handle `focus-in` signal of droplist_grab_window. 50 ''' 51 droplist_grab_window.grab_add() 52 gtk.gdk.pointer_grab( 53 droplist_grab_window.window, 54 True, 55 gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.ENTER_NOTIFY_MASK | gtk.gdk.LEAVE_NOTIFY_MASK, 56 None, None, gtk.gdk.CURRENT_TIME)
57
58 -def droplist_grab_window_focus_out():
59 ''' 60 Handle `focus-out` signal of droplist_grab_window. 61 ''' 62 global root_droplists 63 64 for root_droplist in root_droplists: 65 root_droplist.hide() 66 67 root_droplists = [] 68 69 gtk.gdk.pointer_ungrab(gtk.gdk.CURRENT_TIME) 70 droplist_grab_window.grab_remove()
71
72 -def is_press_on_droplist_grab_window(window):
73 ''' 74 Whether press on droplist of droplist_grab_window. 75 76 @param window: gtk.Window or gtk.gdk.Window 77 ''' 78 for toplevel in gtk.window_list_toplevels(): 79 if isinstance(window, gtk.Window): 80 if window == toplevel: 81 return True 82 elif isinstance(window, gtk.gdk.Window): 83 if window == toplevel.window: 84 return True 85 86 return False
87
88 -def droplist_grab_window_enter_notify(widget, event):
89 ''' 90 Handle `enter-notify` signal of droplist_grab_window. 91 92 @param widget: Droplist widget. 93 @param event: Enter notify event. 94 ''' 95 if event and event.window: 96 event_widget = event.window.get_user_data() 97 if isinstance(event_widget, DroplistScrolledWindow): 98 event_widget.event(event)
99
100 -def droplist_grab_window_leave_notify(widget, event):
101 ''' 102 Handle `leave-notify` signal of droplist_grab_window. 103 104 @param widget: Droplist widget. 105 @param event: Leave notify event. 106 ''' 107 if event and event.window: 108 event_widget = event.window.get_user_data() 109 if isinstance(event_widget, DroplistScrolledWindow): 110 event_widget.event(event)
111
112 -def droplist_grab_window_scroll_event(widget, event):
113 ''' 114 Handle `scroll` signal of droplist_grab_window. 115 116 @param widget: Droplist widget. 117 @param event: Scroll event. 118 ''' 119 global root_droplists 120 121 if event and event.window: 122 for droplist in root_droplists: 123 droplist.item_scrolled_window.event(event)
124
125 -def droplist_grab_window_key_press(widget, event):
126 ''' 127 Handle `key-press-event` signal of droplist_grab_window. 128 129 @param widget: Droplist widget. 130 @param event: Key press event. 131 ''' 132 global root_droplists 133 134 if event and event.window: 135 for droplist in root_droplists: 136 droplist.event(event)
137
138 -def droplist_grab_window_key_release(widget, event):
139 ''' 140 Handle `key-release-event` signal of droplist_grab_window. 141 142 @param widget: Droplist widget. 143 @param event: Key release event. 144 ''' 145 global root_droplists 146 147 if event and event.window: 148 for droplist in root_droplists: 149 droplist.event(event)
150
151 -def droplist_grab_window_button_release(widget, event):
152 ''' 153 Handle `button-release-event` signal of droplist_grab_window. 154 155 @param widget: Droplist widget. 156 @param event: Button release event. 157 ''' 158 global root_droplists 159 global droplist_grab_window_press_flag 160 161 droplist_grab_window_press_flag = False 162 163 if event and event.window: 164 event_widget = event.window.get_user_data() 165 if isinstance(event_widget, DroplistScrolledWindow): 166 event_widget.event(event) 167 else: 168 # Make scrolledbar smaller if release out of scrolled_window area. 169 for droplist in root_droplists: 170 droplist.item_scrolled_window.make_bar_smaller(gtk.ORIENTATION_HORIZONTAL) 171 droplist.item_scrolled_window.make_bar_smaller(gtk.ORIENTATION_VERTICAL)
172
173 -def droplist_grab_window_button_press(widget, event):
174 ''' 175 Handle `button-press-event` signal of droplist_grab_window. 176 177 @param widget: Droplist widget. 178 @param event: Button press event. 179 ''' 180 global droplist_active_item 181 global droplist_grab_window_press_flag 182 183 droplist_grab_window_press_flag = True 184 185 if event and event.window: 186 event_widget = event.window.get_user_data() 187 if is_press_on_droplist_grab_window(event.window): 188 droplist_grab_window_focus_out() 189 elif isinstance(event_widget, DroplistScrolledWindow): 190 event_widget.event(event) 191 elif isinstance(event_widget, Droplist): 192 droplist_item = event_widget.get_droplist_item_at_coordinate(event.get_root_coords()) 193 if droplist_item: 194 droplist_item.item_box.event(event) 195 else: 196 event_widget.event(event) 197 droplist_grab_window_focus_out()
198
199 -def droplist_grab_window_motion_notify(widget, event):
200 ''' 201 Handle `motion-notify` signal of droplist_grab_window. 202 203 @param widget: Droplist widget. 204 @param event: Motion notify signal. 205 ''' 206 global droplist_active_item 207 global droplist_grab_window_press_flag 208 209 if event and event.window: 210 event_widget = event.window.get_user_data() 211 if isinstance(event_widget, DroplistScrolledWindow): 212 event_widget.event(event) 213 elif isinstance(event_widget, Droplist): 214 for droplist in root_droplists: 215 motion_notify_event = gtk.gdk.Event(gtk.gdk.MOTION_NOTIFY) 216 motion_notify_event.window = droplist.item_scrolled_window.vwindow 217 motion_notify_event.send_event = True 218 motion_notify_event.time = event.time 219 motion_notify_event.x = event.x 220 motion_notify_event.y = event.y 221 motion_notify_event.x_root = event.x_root 222 motion_notify_event.y_root = event.y_root 223 motion_notify_event.state = event.state 224 225 droplist.item_scrolled_window.event(motion_notify_event) 226 227 if not droplist_grab_window_press_flag: 228 droplist_item = event_widget.get_droplist_item_at_coordinate(event.get_root_coords()) 229 if droplist_item and isinstance(droplist_item.item_box, gtk.Button): 230 if droplist_active_item: 231 droplist_active_item.item_box.set_state(gtk.STATE_NORMAL) 232 233 droplist_item.item_box.set_state(gtk.STATE_PRELIGHT) 234 droplist_active_item = droplist_item 235 236 enter_notify_event = gtk.gdk.Event(gtk.gdk.ENTER_NOTIFY) 237 enter_notify_event.window = event.window 238 enter_notify_event.time = event.time 239 enter_notify_event.send_event = True 240 enter_notify_event.x_root = event.x_root 241 enter_notify_event.y_root = event.y_root 242 enter_notify_event.x = event.x 243 enter_notify_event.y = event.y 244 enter_notify_event.state = event.state 245 246 droplist_item.item_box.event(enter_notify_event) 247 248 droplist_item.item_box.queue_draw() 249 else: 250 for droplist in root_droplists: 251 motion_notify_event = gtk.gdk.Event(gtk.gdk.MOTION_NOTIFY) 252 motion_notify_event.window = droplist.item_scrolled_window.vwindow 253 motion_notify_event.send_event = True 254 motion_notify_event.time = event.time 255 motion_notify_event.x = event.x 256 motion_notify_event.y = event.y 257 motion_notify_event.x_root = event.x_root 258 motion_notify_event.y_root = event.y_root 259 motion_notify_event.state = event.state 260 261 droplist.item_scrolled_window.event(motion_notify_event)
262 263 droplist_grab_window.connect("button-press-event", droplist_grab_window_button_press) 264 droplist_grab_window.connect("button-release-event", droplist_grab_window_button_release) 265 droplist_grab_window.connect("motion-notify-event", droplist_grab_window_motion_notify) 266 droplist_grab_window.connect("enter-notify-event", droplist_grab_window_enter_notify) 267 droplist_grab_window.connect("leave-notify-event", droplist_grab_window_leave_notify) 268 droplist_grab_window.connect("scroll-event", droplist_grab_window_scroll_event) 269 droplist_grab_window.connect("key-press-event", droplist_grab_window_key_press) 270 droplist_grab_window.connect("key-release-event", droplist_grab_window_key_release) 271
272 -class DroplistScrolledWindow(ScrolledWindow):
273 ''' 274 ScrolledWindow for droplist. 275 ''' 276
277 - def __init__(self, 278 right_space=2, 279 top_bottom_space=3):
280 ''' 281 Initialize DroplistScrolledWindow class. 282 283 @param right_space: the space between right border and the vertical scroolbar. 284 @param top_bottom_space: the space between top border and the vertical scroolbar. 285 ''' 286 ScrolledWindow.__init__(self, right_space, top_bottom_space)
287 288 gobject.type_register(DroplistScrolledWindow) 289
290 -class Droplist(gtk.Window):
291 ''' 292 Droplist. 293 294 @undocumented: expose_item_align 295 @undocumented: droplist_key_press 296 @undocumented: droplist_key_release 297 @undocumented: expose_droplist_frame 298 @undocumented: init_droplist 299 @undocumented: adjust_droplist_position 300 ''' 301 302 __gsignals__ = { 303 "item-selected" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (str, gobject.TYPE_PYOBJECT, int,)), 304 "key-release" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (str, gobject.TYPE_PYOBJECT, int,)), 305 } 306
307 - def __init__(self, 308 items, 309 x_align=ALIGN_START, 310 y_align=ALIGN_START, 311 font_size=DEFAULT_FONT_SIZE, 312 opacity=1.0, 313 padding_x=0, 314 padding_y=0, 315 item_padding_left=6, 316 item_padding_right=32, 317 item_padding_y=3, 318 max_width=None):
319 ''' 320 Initialize Droplist class. 321 322 @param items: A list of item, item format: (item_content, item_value). 323 @param x_align: Horticultural alignment. 324 @param y_align: Vertical alignment. 325 @param font_size: Font size of droplist, default is DEFAULT_FONT_SIZE 326 @param opacity: Opacity of droplist window, default is 1.0. 327 @param padding_x: Padding x, default is 0. 328 @param padding_y: Padding y, default is 0. 329 @param item_padding_left: Padding at left of item, default is 6. 330 @param item_padding_right: Padding at right of item, default is 32. 331 @param item_padding_y: Padding of item vertically, default is 3. 332 @param max_width: Maximum width of droplist, default is None. 333 ''' 334 # Init. 335 gtk.Window.__init__(self, gtk.WINDOW_POPUP) 336 self.items = items 337 self.set_can_focus(True) # can focus to response key-press signal 338 self.add_events(gtk.gdk.ALL_EVENTS_MASK) 339 self.set_decorated(False) 340 self.set_colormap(gtk.gdk.Screen().get_rgba_colormap()) 341 global root_droplists 342 self.font_size = font_size 343 self.x_align = x_align 344 self.y_align = y_align 345 self.subdroplist = None 346 self.root_droplist = None 347 self.offset_x = 0 # use for handle extreme situaiton, such as, droplist show at side of screen 348 self.offset_y = 0 349 self.padding_x = padding_x 350 self.padding_y = padding_y 351 self.item_padding_left = item_padding_left 352 self.item_padding_right = item_padding_right 353 self.item_padding_y = item_padding_y 354 self.max_width = max_width 355 self.item_select_index = 0 356 357 # Init droplist window. 358 self.set_opacity(opacity) 359 self.set_skip_taskbar_hint(True) 360 self.set_keep_above(True) 361 self.connect_after("show", self.init_droplist) 362 363 self.droplist_frame = gtk.Alignment() 364 self.droplist_frame.set(0.5, 0.5, 1.0, 1.0) 365 self.droplist_frame.set_padding(1, 1, 1, 1) 366 367 # Add droplist item. 368 self.item_box = gtk.VBox() 369 self.item_align = gtk.Alignment() 370 self.item_align.set_padding(padding_y, padding_y, padding_x, padding_x) 371 self.item_align.add(self.item_box) 372 self.item_scrolled_window = DroplistScrolledWindow(0, 0) 373 self.add(self.droplist_frame) 374 self.droplist_frame.add(self.item_scrolled_window) 375 self.item_scrolled_window.add_child(self.item_align) 376 self.droplist_items = [] 377 378 if items: 379 for (index, item) in enumerate(items): 380 droplist_item = DroplistItem( 381 self, 382 index, item, font_size, 383 padding_x, padding_y, 384 item_padding_left, item_padding_right, item_padding_y, self.max_width) 385 self.droplist_items.append(droplist_item) 386 self.item_box.pack_start(droplist_item.item_box, False, False) 387 388 self.connect_after("show", self.adjust_droplist_position) 389 self.droplist_frame.connect("expose-event", self.expose_droplist_frame) 390 self.item_align.connect("expose-event", self.expose_item_align) 391 self.connect("key-press-event", self.droplist_key_press) 392 self.connect("key-release-event", self.droplist_key_release) 393 394 self.keymap = { 395 "Home" : self.select_first_item, 396 "End" : self.select_last_item, 397 "Page_Up" : self.scroll_page_up, 398 "Page_Down" : self.scroll_page_down, 399 "Return" : self.press_select_item, 400 "Up" : self.select_prev_item, 401 "Down" : self.select_next_item, 402 "Escape" : self.hide} 403 404 self.select_first_item() 405 self.grab_focus()
406
407 - def get_droplist_width(self):
408 ''' 409 Get droplist width. 410 ''' 411 item_content_width = max(map(lambda item: get_content_size(item.item[0], self.font_size)[0], 412 filter(lambda item: isinstance(item.item_box, gtk.Button), self.droplist_items))) 413 if self.max_width != None: 414 return self.padding_x * 2 + min(self.max_width, 415 self.item_padding_left + self.item_padding_right + int(item_content_width)) 416 else: 417 return self.padding_x * 2 + self.item_padding_left + self.item_padding_right + int(item_content_width)
418
419 - def expose_item_align(self, widget, event):
420 ''' 421 Internal function to handle `expose-event` signal. 422 423 @param widget: Droplist widget. 424 @param event: Expose event. 425 ''' 426 # Init. 427 cr = widget.window.cairo_create() 428 rect = widget.allocation 429 x, y, w, h = rect.x, rect.y, rect.width, rect.height 430 431 # Draw background. 432 cr.set_source_rgba(*alpha_color_hex_to_cairo(ui_theme.get_alpha_color("droplist_mask").get_color_info())) 433 cr.rectangle(x, y, w, h) 434 cr.fill()
435
436 - def get_first_index(self):
437 ''' 438 Get index of first item. 439 440 @return: Return index of first item, or return None if haven't item in droplist. 441 ''' 442 item_indexs = filter(lambda (index, item): isinstance(item.item_box, gtk.Button), enumerate(self.droplist_items)) 443 if len(item_indexs) > 0: 444 return item_indexs[0][0] 445 else: 446 return None
447
448 - def get_last_index(self):
449 ''' 450 Get index of last item. 451 452 @return: Return index of last item, or return None if haven't item in droplist. 453 ''' 454 item_indexs = filter(lambda (index, item): isinstance(item.item_box, gtk.Button), enumerate(self.droplist_items)) 455 if len(item_indexs) > 0: 456 return item_indexs[-1][0] 457 else: 458 return None
459
460 - def get_prev_index(self):
461 ''' 462 Get index of previous item. 463 464 @return: Return index of previous item, or return None if haven't item in droplist. 465 ''' 466 item_indexs = filter(lambda (index, item): isinstance(item.item_box, gtk.Button), enumerate(self.droplist_items)) 467 if len(item_indexs) > 0: 468 index_list = map(lambda (index, item): index, item_indexs) 469 if self.item_select_index in index_list: 470 current_index = index_list.index(self.item_select_index) 471 if current_index > 0: 472 return index_list[current_index - 1] 473 else: 474 return self.item_select_index 475 else: 476 return None 477 else: 478 return None
479
480 - def get_next_index(self):
481 ''' 482 Get index of next item. 483 484 @return: Return index of next item, or return None if haven't item in droplist. 485 ''' 486 item_indexs = filter(lambda (index, item): isinstance(item.item_box, gtk.Button), enumerate(self.droplist_items)) 487 if len(item_indexs) > 0: 488 index_list = map(lambda (index, item): index, item_indexs) 489 if self.item_select_index in index_list: 490 current_index = index_list.index(self.item_select_index) 491 if current_index < len(index_list) - 1: 492 return index_list[current_index + 1] 493 else: 494 return self.item_select_index 495 else: 496 return None 497 else: 498 return None
499
500 - def get_select_item_rect(self, item_index=None):
501 ''' 502 Get item rectangle with given index. 503 504 @param item_index: If item_index is None, use select index. 505 506 @return: Return (x, y, w, h) rectangle for match item. 507 ''' 508 if item_index == None: 509 item_index = self.item_select_index 510 item_offset_y = sum(map(lambda item: item.item_box_height, self.droplist_items)[0:item_index]) 511 item_rect = self.droplist_items[item_index].item_box.get_allocation() 512 return (0, item_offset_y, item_rect.width, item_rect.height)
513
514 - def active_item(self, item_index=None):
515 ''' 516 Select item with given index. 517 518 @param item_index: If item_index is None, use select index. 519 ''' 520 global droplist_active_item 521 522 if item_index == None: 523 item_index = self.item_select_index 524 525 if droplist_active_item: 526 droplist_active_item.item_box.set_state(gtk.STATE_NORMAL) 527 528 item = self.droplist_items[item_index] 529 item.item_box.set_state(gtk.STATE_PRELIGHT) 530 droplist_active_item = item
531
532 - def select_first_item(self):
533 ''' 534 Select first item. 535 ''' 536 if len(self.droplist_items) > 0: 537 first_index = self.get_first_index() 538 if first_index != None: 539 self.item_select_index = first_index 540 self.active_item() 541 542 # Scroll to top. 543 vadjust = self.item_scrolled_window.get_vadjustment() 544 vadjust.set_value(vadjust.get_lower())
545
546 - def select_last_item(self):
547 ''' 548 Select last item. 549 ''' 550 if len(self.droplist_items) > 0: 551 last_index = self.get_last_index() 552 if last_index != None: 553 self.item_select_index = last_index 554 self.active_item() 555 556 # Scroll to bottom. 557 vadjust = self.item_scrolled_window.get_vadjustment() 558 vadjust.set_value(vadjust.get_upper() - vadjust.get_page_size())
559
560 - def select_prev_item(self):
561 ''' 562 Select previous item. 563 ''' 564 if len(self.droplist_items) > 0: 565 prev_index = self.get_prev_index() 566 if prev_index != None: 567 global droplist_active_item 568 569 if droplist_active_item: 570 if self.item_select_index > 0: 571 self.item_select_index = prev_index 572 self.active_item() 573 574 # Make item in visible area. 575 (item_x, item_y, item_width, item_height) = self.get_select_item_rect() 576 vadjust = self.item_scrolled_window.get_vadjustment() 577 if item_y < vadjust.get_value(): 578 vadjust.set_value(item_y) 579 else: 580 self.select_first_item()
581
582 - def select_next_item(self):
583 ''' 584 Select next item. 585 ''' 586 if len(self.droplist_items) > 0: 587 next_index = self.get_next_index() 588 if next_index != None: 589 global droplist_active_item 590 591 if droplist_active_item: 592 if self.item_select_index < len(self.droplist_items) - 1: 593 self.item_select_index = next_index 594 self.active_item() 595 596 # Make item in visible area. 597 (item_x, item_y, item_width, item_height) = self.get_select_item_rect() 598 vadjust = self.item_scrolled_window.get_vadjustment() 599 if self.padding_y + item_y + item_height > vadjust.get_value() + vadjust.get_page_size(): 600 vadjust.set_value(self.padding_y * 2 + item_y + item_height - vadjust.get_page_size()) 601 else: 602 self.select_first_item()
603
605 ''' 606 Scroll page to select item. 607 ''' 608 (item_x, item_y, item_width, item_height) = self.get_select_item_rect() 609 vadjust = self.item_scrolled_window.get_vadjustment() 610 vadjust.set_value(min(max(vadjust.get_lower(), item_y - self.padding_y * 2), 611 vadjust.get_upper() - vadjust.get_page_size()))
612
613 - def scroll_page_up(self):
614 ''' 615 Scroll page up. 616 ''' 617 if len(self.droplist_items) > 0: 618 # Scroll page up. 619 vadjust = self.item_scrolled_window.get_vadjustment() 620 vadjust.set_value(max(vadjust.get_lower(), vadjust.get_value() - vadjust.get_page_size())) 621 622 # Select nearest item. 623 item_infos = map(lambda (index, item): (index, self.get_select_item_rect(index)), enumerate(self.droplist_items)) 624 for (index, (item_x, item_y, item_width, item_height)) in item_infos: 625 if item_y + self.padding_y > vadjust.get_value(): 626 self.item_select_index = index 627 self.active_item() 628 break
629
630 - def scroll_page_down(self):
631 ''' 632 Scroll page down. 633 ''' 634 if len(self.droplist_items) > 0: 635 # Scroll page up. 636 vadjust = self.item_scrolled_window.get_vadjustment() 637 vadjust.set_value(min(vadjust.get_upper() - vadjust.get_page_size(), 638 vadjust.get_value() + vadjust.get_page_size())) 639 640 # Select nearest item. 641 item_infos = map(lambda (index, item): (index, self.get_select_item_rect(index)), enumerate(self.droplist_items)) 642 item_infos.reverse() 643 for (index, (item_x, item_y, item_width, item_height)) in item_infos: 644 if item_y + item_height + self.padding_y < vadjust.get_value() + vadjust.get_page_size(): 645 self.item_select_index = index 646 self.active_item() 647 break
648
649 - def press_select_item(self):
650 ''' 651 Press select item. 652 ''' 653 if len(self.droplist_items) > 0: 654 if 0 <= self.item_select_index < len(self.droplist_items): 655 self.droplist_items[self.item_select_index].wrap_droplist_clicked_action()
656
657 - def droplist_key_press(self, widget, event):
658 ''' 659 Internal function for `key-press-event` signal. 660 661 @param widget: Droplist widget. 662 @param event: Key press event. 663 ''' 664 key_name = get_keyevent_name(event) 665 if self.keymap.has_key(key_name): 666 self.keymap[key_name]() 667 668 return True
669
670 - def droplist_key_release(self, widget, event):
671 ''' 672 Internal function for `key-release-event` signal. 673 674 @param widget: Droplist widget. 675 @param event: Key release event. 676 ''' 677 self.emit("key-release", 678 self.items[self.item_select_index][0], 679 self.items[self.item_select_index][1], 680 self.item_select_index)
681
682 - def expose_droplist_frame(self, widget, event):
683 ''' 684 Callback for `expose-event` siangl of droplist frame. 685 686 @param widget: Droplist widget. 687 @param event: Expose event. 688 ''' 689 cr = widget.window.cairo_create() 690 rect = widget.allocation 691 692 with cairo_disable_antialias(cr): 693 cr.set_line_width(1) 694 cr.set_source_rgb(*color_hex_to_cairo(ui_theme.get_color("droplist_frame").get_color())) 695 cr.rectangle(rect.x, rect.y, rect.width, rect.height) 696 cr.fill()
697
698 - def get_droplist_item_at_coordinate(self, (x, y)):
699 ''' 700 Get droplist item at coordinate, return None if haven't any droplist item at given coordinate. 701 702 @param x: X coordiante. 703 @param y: Y coordiante. 704 705 @return: Return match item with given coordinate, return None if haven't any item match coordinate. 706 ''' 707 match_droplist_item = None 708 709 item_heights = map(lambda item: item.item_box_height, self.droplist_items) 710 item_offsets = map(lambda (index, height): sum(item_heights[0:index]), enumerate(item_heights)) 711 712 vadjust = self.item_scrolled_window.get_vadjustment() 713 (scrolled_window_x, scrolled_window_y) = get_widget_root_coordinate(self.item_scrolled_window, WIDGET_POS_TOP_LEFT) 714 for (index, droplist_item) in enumerate(self.droplist_items): 715 item_rect = droplist_item.item_box.get_allocation() 716 if is_in_rect((x, y), (scrolled_window_x, 717 scrolled_window_y + item_offsets[index] - (vadjust.get_value() - vadjust.get_lower()), 718 item_rect.width, 719 item_rect.height)): 720 match_droplist_item = droplist_item 721 break 722 723 return match_droplist_item
724
725 - def init_droplist(self, widget):
726 ''' 727 Callback after `show` signal. 728 729 @param widget: Droplist widget. 730 ''' 731 global root_droplists 732 droplist_grab_window_focus_out() 733 734 if not gtk.gdk.pointer_is_grabbed(): 735 droplist_grab_window_focus_in() 736 737 if not self in root_droplists: 738 root_droplists.append(self)
739
740 - def show(self, (x, y), (offset_x, offset_y)=(0, 0)):
741 ''' 742 Show droplist. 743 744 @param x: Show x coordinate. 745 @param y: Show y coordinate. 746 @param offset_x: Offset x value when droplist haven't space to show in origin coordinate, default is 0. 747 @param offset_y: Offset y value when droplist haven't space to show in origin coordinate, default is 0. 748 ''' 749 # Init offset. 750 self.expect_x = x 751 self.expect_y = y 752 self.offset_x = offset_x 753 self.offset_y = offset_y 754 755 # Show. 756 self.show_all()
757
758 - def adjust_droplist_position(self, widget):
759 ''' 760 Internal function to adjust droplist position after `realize` signal. 761 762 @param widget: Droplist widget. 763 ''' 764 # Adjust coordinate. 765 (screen_width, screen_height) = get_screen_size(self) 766 767 droplist_width = 0 768 for droplist_item in self.droplist_items: 769 if droplist_width == 0 and isinstance(droplist_item.item_box, gtk.Button): 770 droplist_width = droplist_item.item_box_width 771 droplist_width += self.padding_x * 2 772 droplist_height = self.allocation.height 773 774 if self.x_align == ALIGN_START: 775 dx = self.expect_x 776 elif self.x_align == ALIGN_MIDDLE: 777 dx = self.expect_x - droplist_width / 2 778 else: 779 dx = self.expect_x - droplist_width 780 781 if self.y_align == ALIGN_START: 782 dy = self.expect_y 783 elif self.y_align == ALIGN_MIDDLE: 784 dy = self.expect_y - droplist_height / 2 785 else: 786 dy = self.expect_y - droplist_height 787 788 if self.expect_x + droplist_width > screen_width: 789 dx = self.expect_x - droplist_width + self.offset_x 790 if self.expect_y + droplist_height > screen_height: 791 dy = self.expect_y - droplist_height + self.offset_y 792 793 self.move(dx, dy)
794
795 - def hide(self):
796 ''' 797 Hide droplist. 798 ''' 799 # Hide current droplist window. 800 self.hide_all() 801 802 # Reset. 803 self.subdroplist = None 804 self.root_droplist = None
805 806 gobject.type_register(Droplist) 807
808 -class DroplistItem(object):
809 ''' 810 DroplistItem for L{ I{Droplist} <Droplist>}. 811 812 @undocumented: create_separator_item 813 @undocumented: create_droplist_item 814 @undocumented: realize_item_box 815 @undocumented: wrap_droplist_clicked_action 816 @undocumented: expose_droplist_item 817 ''' 818
819 - def __init__(self, 820 droplist, 821 index, 822 item, 823 font_size, 824 droplist_padding_x, 825 droplist_padding_y, 826 item_padding_left, 827 item_padding_right, 828 item_padding_y, 829 max_width):
830 ''' 831 Initialize DroplistItem class. 832 833 @param droplist: Droplist. 834 @param index: Drop item index. 835 @param item: Drop item, format (item_content, item_value) 836 @param font_size: Drop item font size. 837 @param droplist_padding_x: Padding x of droplist. 838 @param droplist_padding_y: Padding y of droplist. 839 @param item_padding_left: Padding at left of item. 840 @param item_padding_right: Padding at right of item. 841 @param item_padding_y: Padding at top or bottom of item. 842 @param max_width: Maximum width of droplist item. 843 ''' 844 # Init. 845 self.droplist = droplist 846 self.index = index 847 self.item = item 848 self.font_size = font_size 849 self.droplist_padding_x = droplist_padding_x 850 self.droplist_padding_y = droplist_padding_y 851 self.item_padding_left = item_padding_left 852 self.item_padding_right = item_padding_right 853 self.item_padding_y = item_padding_y 854 self.subdroplist_active = False 855 self.max_width = max_width 856 self.arrow_padding_x = 5 857 858 # Create. 859 if self.item: 860 self.create_droplist_item() 861 else: 862 self.create_separator_item()
863
864 - def create_separator_item(self):
865 ''' 866 Internal function, create separator item. 867 ''' 868 self.item_box = HSeparator( 869 ui_theme.get_shadow_color("h_separator").get_color_info(), 870 self.item_padding_left, 871 self.item_padding_y) 872 self.item_box_height = self.item_padding_y * 2 + 1
873
874 - def create_droplist_item(self):
875 ''' 876 Internal function, create droplist item. 877 ''' 878 # Get item information. 879 (item_content, item_value) = self.item[0:2] 880 881 # Create button. 882 self.item_box = gtk.Button() 883 884 # Expose button. 885 self.item_box.connect( 886 "expose-event", 887 lambda w, e: self.expose_droplist_item( 888 w, e, item_content)) 889 890 # Wrap droplist aciton. 891 self.item_box.connect("button-press-event", lambda w, e: self.wrap_droplist_clicked_action()) 892 893 self.item_box.connect("realize", lambda w: self.realize_item_box(w, item_content))
894
895 - def realize_item_box(self, widget, item_content):
896 ''' 897 Internal function, realize item box. 898 899 @param widget: DropItem widget. 900 @param item_content: Item content. 901 ''' 902 # Set button size. 903 (width, height) = get_content_size(item_content, self.font_size) 904 self.item_box_height = self.item_padding_y * 2 + int(height) 905 self.item_box_width = self.item_padding_left + self.item_padding_right + int(width) 906 907 if self.max_width != None: 908 self.item_box_width = min(self.item_box_width, self.max_width) 909 else: 910 self.item_box_width = self.item_box_width 911 912 self.item_box.set_size_request(self.item_box_width, self.item_box_height)
913
915 ''' 916 Internal function to wrap clicked action. 917 ''' 918 # Emit item-selected signal. 919 self.droplist.emit("item-selected", self.item[0], self.item[1], self.index) 920 921 # Hide droplist. 922 droplist_grab_window_focus_out()
923
924 - def expose_droplist_item(self, widget, event, item_content):
925 ''' 926 Internal function to handle `expose-event` signal of item. 927 928 @param widget: DropItem widget. 929 @param event: Expose event. 930 @param item_content: Item content. 931 ''' 932 # Init. 933 cr = widget.window.cairo_create() 934 rect = widget.allocation 935 font_color = ui_theme.get_color("menu_font").get_color() 936 937 # Draw select effect. 938 if self.subdroplist_active or widget.state in [gtk.STATE_PRELIGHT, gtk.STATE_ACTIVE]: 939 # Draw background. 940 draw_vlinear(cr, rect.x, rect.y, rect.width, rect.height, 941 ui_theme.get_shadow_color("menu_item_select").get_color_info()) 942 943 # Set font color. 944 font_color = ui_theme.get_color("menu_select_font").get_color() 945 946 # Draw item content. 947 draw_text(cr, item_content, 948 rect.x + self.item_padding_left, 949 rect.y, 950 rect.width, 951 rect.height, 952 self.font_size, font_color, 953 ) 954 955 # Propagate expose to children. 956 propagate_expose(widget, event) 957 958 return True
959