Package dtk :: Package ui :: Module utils

Source Code for Module dtk.ui.utils

   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 contextlib import contextmanager  
  24  import cairo 
  25  import gobject 
  26  import gtk 
  27  import math 
  28  import os 
  29  import pango 
  30  import pangocairo 
  31  import socket 
  32  import subprocess 
  33  import time 
  34  from constant import (WIDGET_POS_TOP_LEFT, WIDGET_POS_TOP_RIGHT,  
  35                        WIDGET_POS_TOP_CENTER, WIDGET_POS_BOTTOM_LEFT,  
  36                        WIDGET_POS_BOTTOM_CENTER, WIDGET_POS_BOTTOM_RIGHT,  
  37                        WIDGET_POS_LEFT_CENTER, WIDGET_POS_RIGHT_CENTER,  
  38                        WIDGET_POS_CENTER, DEFAULT_FONT, COLOR_NAME_DICT,  
  39                        BLACK_COLOR_MAPPED, WHITE_COLOR_MAPPED, SIMILAR_COLOR_SEQUENCE, 
  40                        DEFAULT_FONT_SIZE) 
41 42 -def tree_view_get_toplevel_node_count(treeview):
43 ''' 44 Get node count number of TreeView. 45 46 @param treeview: Gtk.TreeView instance. 47 @return: Return number of node. 48 49 Return 0 if treeview haven't model. 50 ''' 51 model = treeview.get_model() 52 if model != None: 53 return model.iter_n_children(None) 54 else: 55 return 0
56
57 -def tree_view_get_selected_path(treeview):
58 ''' 59 Get selected path of TreeView. 60 61 @param treeview: Gtk.TreeView instance. 62 @return: Return selected path of treeview. 63 64 Return None if haven't any path selected. 65 ''' 66 selection = treeview.get_selection() 67 (_, tree_paths) = selection.get_selected_rows() 68 if len(tree_paths) != 0: 69 return (tree_paths[0])[0] 70 else: 71 return None
72
73 -def tree_view_focus_first_toplevel_node(treeview):
74 ''' 75 Focus first toplevel node of TreeView. 76 77 @param treeview: Gtk.TreeView instance. 78 ''' 79 treeview.set_cursor((0))
80
81 -def tree_view_focus_last_toplevel_node(treeview):
82 ''' 83 Focus last toplevel node of TreeView. 84 85 @param treeview: Gtk.TreeView instance. 86 ''' 87 node_count = tree_view_get_toplevel_node_count(treeview) 88 if node_count > 0: 89 path = (node_count - 1) 90 else: 91 path = (0) 92 treeview.set_cursor(path)
93
94 -def tree_view_scroll_vertical(treeview, scroll_up=True):
95 ''' 96 Scroll TreeView vertically. 97 98 @param treeview: Gtk.TreeView instance. 99 @param scroll_up: Defalut value is True, set as False if you want scroll down. 100 ''' 101 # Init. 102 scroll_num = 9 103 candidate_count = tree_view_get_toplevel_node_count(treeview) 104 cursor = treeview.get_cursor() 105 (path, column) = cursor 106 max_candidate = candidate_count - 1 107 108 # Get candidate at cursor. 109 if path == None: 110 current_candidate = max_candidate 111 else: 112 (current_candidate,) = path 113 114 # Set cursor to new candidate. 115 if scroll_up: 116 new_candidate = max(0, current_candidate - scroll_num) 117 else: 118 new_candidate = min(current_candidate + scroll_num, max_candidate) 119 120 treeview.set_cursor((new_candidate))
121
122 -def tree_view_focus_next_toplevel_node(treeview):
123 ''' 124 Focus next toplevel node of TreeView. 125 126 @param treeview: Gtk.TreeView instance. 127 ''' 128 selected_path = tree_view_get_selected_path(treeview) 129 if selected_path != None: 130 node_count = tree_view_get_toplevel_node_count(treeview) 131 if selected_path < node_count - 1: 132 treeview.set_cursor((selected_path + 1))
133
134 -def tree_view_focus_prev_toplevel_node(treeview):
135 ''' 136 Focus previous toplevel node of TreeView. 137 138 @param treeview: Gtk.TreeView instance. 139 ''' 140 selected_path = tree_view_get_selected_path(treeview) 141 if selected_path != None: 142 if selected_path > 0: 143 treeview.set_cursor((selected_path - 1))
144
145 -def get_entry_text(entry):
146 ''' 147 Get text of entry. 148 149 @param entry: Gtk.Entry instance. 150 @return: Return text of entry. 151 ''' 152 return entry.get_text().split(" ")[0]
153
154 -def set_cursor(cursor_widget, cursor_type=None):
155 ''' 156 Set cursor type with given widget. 157 158 @param cursor_widget: Gtk.Widget or Gdk.Window instance. 159 @param cursor_type: The cursor type of gtk.gdk.Cursor, please set with None if you want reset widget's cursor as default. 160 @return: Always return False 161 ''' 162 if isinstance(cursor_widget, gtk.Widget): 163 cursor_window = cursor_widget.window 164 elif isinstance(cursor_widget, gtk.gdk.Window): 165 cursor_window = cursor_widget 166 else: 167 print "set_cursor: impossible!" 168 169 if cursor_type == None: 170 cursor_window.set_cursor(None) 171 else: 172 cursor_window.set_cursor(gtk.gdk.Cursor(cursor_type)) 173 174 return False
175
176 -def set_clickable_cursor(widget):
177 ''' 178 Show gtk.gdk.HAND2 cursor when mouse hover widget. 179 180 @param widget: Gtk.Widget instance. 181 ''' 182 set_hover_cursor(widget, gtk.gdk.HAND2)
183
184 -def set_hover_cursor(widget, cursor_type):
185 ''' 186 Set cursor type when mouse hover widget. 187 188 @param widget: Gtk.Widget instance. 189 @param cursor_type: The cursor type of gtk.gdk.Cursor. 190 ''' 191 widget.connect("enter-notify-event", lambda w, e: set_cursor(w, cursor_type)) 192 widget.connect("leave-notify-event", lambda w, e: set_cursor(w))
193
194 -def get_widget_root_coordinate(widget, pos_type=WIDGET_POS_BOTTOM_CENTER):
195 ''' 196 Get root coordinate with given widget. 197 198 @param widget: Gtk.Widget instance. 199 @param pos_type: The position of widget's area, you can set with below constants: 200 - WIDGET_POS_TOP_LEFT 201 - WIDGET_POS_TOP_RIGHT 202 - WIDGET_POS_TOP_CENTER 203 - WIDGET_POS_BOTTOM_LEFT 204 - WIDGET_POS_BOTTOM_RIGHT 205 - WIDGET_POS_BOTTOM_CENTER 206 - WIDGET_POS_LEFT_CENTER 207 - WIDGET_POS_RIGHT_CENTER 208 - WIDGET_POS_CENTER 209 @return: Return (x, y) as root coordination. 210 ''' 211 # Get coordinate. 212 (wx, wy) = widget.window.get_origin() 213 toplevel_window = widget.get_toplevel() 214 if toplevel_window: 215 (x, y) = widget.translate_coordinates(toplevel_window, wx, wy) 216 else: 217 (x, y) = (wx, wy) 218 219 # Get offset. 220 rect = widget.allocation 221 if pos_type == WIDGET_POS_TOP_LEFT: 222 offset_x = 0 223 offset_y = 0 224 elif pos_type == WIDGET_POS_TOP_RIGHT: 225 offset_x = rect.width 226 offset_y = 0 227 elif pos_type == WIDGET_POS_TOP_CENTER: 228 offset_x = rect.width / 2 229 offset_y = 0 230 elif pos_type == WIDGET_POS_BOTTOM_LEFT: 231 offset_x = 0 232 offset_y = rect.height 233 elif pos_type == WIDGET_POS_BOTTOM_RIGHT: 234 offset_x = rect.width 235 offset_y = rect.height 236 elif pos_type == WIDGET_POS_BOTTOM_CENTER: 237 offset_x = rect.width / 2 238 offset_y = rect.height 239 elif pos_type == WIDGET_POS_LEFT_CENTER: 240 offset_x = 0 241 offset_y = rect.height / 2 242 elif pos_type == WIDGET_POS_RIGHT_CENTER: 243 offset_x = rect.width 244 offset_y = rect.height / 2 245 elif pos_type == WIDGET_POS_CENTER: 246 offset_x = rect.width / 2 247 offset_y = rect.height / 2 248 249 return (x + offset_x, y + offset_y)
250
251 -def get_event_root_coords(event):
252 ''' 253 Get root coordinate with given event. 254 255 @param event: Gdk.Event instance, general, we get event instance from gtk signal callback. 256 @return: Return (x, y) as event's root coordination. 257 ''' 258 (rx, ry) = event.get_root_coords() 259 return (int(rx), int(ry))
260
261 -def get_event_coords(event):
262 ''' 263 Get coordinate with given event. 264 265 @param event: Gdk.Event instance, general, we get event instance from gtk signal callback. 266 @return: Return (x, y) as event's coordination. 267 ''' 268 (rx, ry) = event.get_coords() 269 return (int(rx), int(ry))
270
271 -def propagate_expose(widget, event):
272 ''' 273 Propagate expose to children. 274 275 General, this function use at last position of `expose_event` callback to make child redraw after parent widget. 276 277 And you must put \"return True\" after \"propagate_expose(widget, event)\". 278 279 Example: 280 281 >>> def expose_event_callback(widget, event): 282 >>> # Do something. 283 >>> 284 >>> propagate_expose(widget, event) 285 >>> return True 286 287 @param widget: Gtk.Container instance. 288 289 This function do nothing if widget is not Gtk.Container instance or haven't any child widget. 290 291 @param event: Gdk.Event instance. 292 ''' 293 if "get_child" in dir(widget) and widget.get_child() != None: 294 widget.propagate_expose(widget.get_child(), event)
295
296 -def move_window(widget, event, window):
297 ''' 298 Move window with given widget and event. 299 300 This function generic use for move window when mouse drag on target widget. 301 302 @param widget: Gtk.Widget instance to drag. 303 @param event: Gdk.Event instance, generic, event come from gtk signal callback. 304 @param window: Gtk.Window instance. 305 ''' 306 if is_left_button(event): 307 window.begin_move_drag( 308 event.button, 309 int(event.x_root), 310 int(event.y_root), 311 event.time) 312 313 return False
314
315 -def resize_window(widget, event, window, edge):
316 ''' 317 Resize window with given widget and event. 318 319 This function generic use for resize window when mouse drag on target widget. 320 321 @param widget: Gtk.Widget instance to drag. 322 @param event: Gdk.Event instance, generic, event come from gtk signal callback. 323 @param window: Gtk.Window instance. 324 ''' 325 if is_left_button(event): 326 window.begin_resize_drag( 327 edge, 328 event.button, 329 int(event.x_root), 330 int(event.y_root), 331 event.time) 332 333 return False
334
335 -def add_in_scrolled_window(scrolled_window, widget, shadow_type=gtk.SHADOW_NONE):
336 ''' 337 Add widget in scrolled_window. 338 339 Wrap function `add_with_viewport` with shadow type of Gtk.Viewport. 340 341 @param scrolled_window: Gtk.ScrolledWindow instance. 342 @param widget: Gtk.Widget instance. 343 @param shadow_type: Shadow type of Viewport, default is gtk.SHADOW_NONE. 344 ''' 345 scrolled_window.add_with_viewport(widget) 346 viewport = scrolled_window.get_child() 347 if viewport != None: 348 viewport.set_shadow_type(shadow_type) 349 else: 350 print "add_in_scrolled_window: Impossible, no viewport widget in ScrolledWindow!"
351
352 -def is_single_click(event):
353 ''' 354 Whether an event is single click event. 355 356 @param event: gtk.gdk.BUTTON_PRESS event. 357 @return: Return True if event is single click event. 358 ''' 359 return event.button == 1 and event.type == gtk.gdk.BUTTON_PRESS
360
361 -def is_double_click(event):
362 ''' 363 Whether an event is double click event. 364 365 @param event: gtk.gdk.BUTTON_PRESS event. 366 @return: Return True if event is double click event. 367 ''' 368 return event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS
369
370 -def is_left_button(event):
371 ''' 372 Whether event is left button event. 373 374 @param event: gtk.gdk.BUTTON_PRESS event. 375 @return: Return True if event is left button event. 376 ''' 377 return event.button == 1
378
379 -def is_right_button(event):
380 ''' 381 Whehter event is right button event. 382 383 @param event: gtk.gdk.BUTTON_PRESS event. 384 @return: Return True if event is right button event. 385 ''' 386 return event.button == 3
387
388 -def is_middle_button(event):
389 ''' 390 Whehter event is middle button event. 391 392 @param event: gtk.gdk.BUTTON_PRESS event. 393 @return: Return True if event is middle button event. 394 ''' 395 return event.button == 2
396
397 -def foreach_container(widget, callback):
398 ''' 399 Make callback call for all children of widget. 400 401 @param widget: Gtk.Container instance. 402 @param callback: Callback. 403 ''' 404 callback(widget) 405 406 if isinstance(widget, gtk.Container): 407 foreach_recursive(widget, callback)
408
409 -def foreach_recursive(container, callback):
410 ''' 411 Helper function for L{ I{foreach_container} <foreach_container>}. 412 413 @param container: Gtk.Container instance. 414 @param callback: Callback. 415 ''' 416 container.foreach(lambda w: foreach_container(w, callback))
417
418 -def container_remove_all(container):
419 ''' 420 Handy function to remove all children widget from container. 421 422 @param container: Gtk.Container instance. 423 ''' 424 container.foreach(lambda widget: container.remove(widget))
425
426 -def get_screen_size(widget):
427 ''' 428 Get screen size from the toplevel window associated with widget. 429 430 @param widget: Gtk.Widget instance. 431 @return: Return screen size as (screen_width, screen_height) 432 433 ''' 434 screen = widget.get_screen() 435 width = screen.get_width() 436 height = screen.get_height() 437 return (width, height)
438
439 -def is_in_rect((tx, ty), (x, y, w, h)):
440 ''' 441 Whether target coordinate in given rectangle. 442 443 @param tx: Target x coordinate. 444 @param ty: Target y coordinate. 445 @param x: X coordinate of rectangle area. 446 @param y: X coordinate of rectangle area. 447 @param w: Width of rectangle area. 448 @param h: Height of rectangle area. 449 @return: Return True if target coordinate in given rectangle. 450 ''' 451 return (tx >= x and tx <= x + w and ty >= y and ty <= y + h)
452
453 -def scroll_to_top(scrolled_window):
454 ''' 455 Scroll scrolled_window to top position. 456 457 @param scrolled_window: Gtk.ScrolledWindow instance. 458 ''' 459 scrolled_window.get_vadjustment().set_value(0)
460
461 -def scroll_to_bottom(scrolled_window):
462 ''' 463 Scroll scrolled_window to bottom position. 464 465 @param scrolled_window: Gtk.ScrolledWindow instance. 466 ''' 467 vadjust = scrolled_window.get_vadjustment() 468 vadjust.set_value(vadjust.get_upper() - vadjust.get_page_size())
469
470 -def get_content_size(text, text_size=DEFAULT_FONT_SIZE, text_font=DEFAULT_FONT, wrap_width=None):
471 ''' 472 Get text size, in pixel. 473 474 @param text: String or markup string. 475 @param text_size: Text size, in pixel. 476 @param text_font: Text font. 477 @param wrap_width: The width of wrap rule, default don't wrap. 478 @return: Return text size as (text_width, text_height), return (0, 0) if occur error. 479 ''' 480 if text: 481 surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0) # don't need give size 482 cr = cairo.Context(surface) 483 context = pangocairo.CairoContext(cr) 484 layout = context.create_layout() 485 layout.set_font_description(pango.FontDescription("%s %s" % (text_font, text_size))) 486 layout_set_markup(layout, text) 487 if wrap_width == None: 488 layout.set_single_paragraph_mode(True) 489 else: 490 layout.set_width(wrap_width * pango.SCALE) 491 layout.set_single_paragraph_mode(False) 492 layout.set_wrap(pango.WRAP_WORD) 493 494 return layout.get_pixel_size() 495 else: 496 return (0, 0)
497
498 -def create_directory(directory, remove_first=False):
499 ''' 500 Create directory. 501 502 @param directory: Target directory to create. 503 @param remove_first: If you want remove directory when directory has exist, set it as True. 504 ''' 505 if remove_first and os.path.exists(directory): 506 remove_directory(directory) 507 508 if not os.path.exists(directory): 509 os.makedirs(directory)
510
511 -def remove_file(path):
512 ''' 513 Remove file if file exist. 514 515 @param path: Target path to remove. 516 ''' 517 if os.path.exists(path): 518 os.remove(path)
519
520 -def remove_directory(path):
521 """ 522 Remove directory recursively, equivalent to command `rm -rf path`. 523 524 @param path: Target directory to remove. 525 """ 526 if os.path.exists(path): 527 for i in os.listdir(path): 528 full_path = os.path.join(path, i) 529 if os.path.isdir(full_path): 530 remove_directory(full_path) 531 else: 532 os.remove(full_path) 533 os.rmdir(path)
534
535 -def touch_file(filepath):
536 ''' 537 Touch file, equivalent to command `touch filepath`. 538 539 If filepath's parent directory is not exist, this function will create parent directory first. 540 541 @param filepath: Target path to touch. 542 ''' 543 # Create directory first. 544 dir = os.path.dirname(filepath) 545 if not os.path.exists(dir): 546 os.makedirs(dir) 547 548 # Touch file. 549 open(filepath, "w").close()
550
551 -def read_file(filepath, check_exists=False):
552 ''' 553 Read file content. 554 555 @param filepath: Target filepath. 556 @param check_exists: Whether check file is exist, default is False. 557 558 @return: Return \"\" if check_exists is True and filepath not exist. 559 560 Otherwise return file's content. 561 ''' 562 if check_exists and not os.path.exists(filepath): 563 return "" 564 else: 565 r_file = open(filepath, "r") 566 content = r_file.read() 567 r_file.close() 568 569 return content
570
571 -def read_first_line(filepath, check_exists=False):
572 ''' 573 Read first line of file. 574 575 @param filepath: Target filepath. 576 @param check_exists: Whether check file is exist, default is False. 577 @return: Return \"\" if check_exists is True and filepath not exist. 578 579 Otherwise return file's first line. 580 ''' 581 if check_exists and not os.path.exists(filepath): 582 return "" 583 else: 584 r_file = open(filepath, "r") 585 content = r_file.readline().split("\n")[0] 586 r_file.close() 587 588 return content
589
590 -def eval_file(filepath, check_exists=False):
591 ''' 592 Eval file content. 593 594 @param filepath: Target filepath. 595 @param check_exists: Whether check file is exist, default is False. 596 @return: Return None if check_exists is True and file not exist. 597 598 Return None if occur error when eval file. 599 600 Otherwise return file content as python structure. 601 ''' 602 if check_exists and not os.path.exists(filepath): 603 return None 604 else: 605 try: 606 read_file = open(filepath, "r") 607 content = eval(read_file.read()) 608 read_file.close() 609 610 return content 611 except Exception, e: 612 print e 613 614 return None
615
616 -def write_file(filepath, content):
617 ''' 618 Write file with given content. 619 620 @param filepath: Target filepath to write. 621 @param content: File content to write. 622 ''' 623 f = open(filepath, "w") 624 f.write(content) 625 f.close()
626
627 -def kill_process(proc):
628 ''' 629 Kill process. 630 631 @param proc: Subprocess instance. 632 ''' 633 try: 634 if proc != None: 635 proc.kill() 636 except Exception, e: 637 print "kill_process got error: %s" % (e)
638
639 -def get_command_output_first_line(commands):
640 ''' 641 Run command and return first line of output. 642 643 @param commands: Input commands. 644 @return: Return first line of command output. 645 ''' 646 process = subprocess.Popen(commands, stdout=subprocess.PIPE) 647 process.wait() 648 return process.stdout.readline()
649
650 -def get_command_output(commands):
651 ''' 652 Run command and return output. 653 654 @param commands: Input commands. 655 @return: Return command output. 656 ''' 657 process = subprocess.Popen(commands, stdout=subprocess.PIPE) 658 process.wait() 659 return process.stdout.readlines()
660
661 -def run_command(command):
662 ''' 663 Run command silencely. 664 665 @param command: Input command. 666 ''' 667 subprocess.Popen("nohup %s > /dev/null 2>&1" % (command), shell=True)
668
669 -def get_os_version():
670 ''' 671 Get OS version with command `lsb_release -i`. 672 673 @return: Return OS version string. 674 ''' 675 version_infos = get_command_output_first_line(["lsb_release", "-i"]).split() 676 677 if len(version_infos) > 0: 678 return version_infos[-1] 679 else: 680 return ""
681
682 -def get_current_time(time_format="%Y-%m-%d %H:%M:%S"):
683 ''' 684 Get current time with given time format. 685 686 @param time_format: Time format, default is %Y-%m-%d %H:%M:%S 687 @return: Return current time with given time format. 688 ''' 689 return time.strftime(time_format, time.localtime())
690
691 -def add_in_list(e_list, element):
692 ''' 693 Add element in list, don't add if element has in list. 694 695 @param e_list: List to insert. 696 @param element: Element will insert to list. 697 ''' 698 if not element in e_list: 699 e_list.append(element)
700
701 -def remove_from_list(e_list, element):
702 ''' 703 Try remove element from list, do nothing if element not in list. 704 705 @param e_list: List to remove. 706 @param element: Element try to remove from list. 707 ''' 708 if element in e_list: 709 e_list.remove(element)
710
711 -def sort_alpha(e_list):
712 ''' 713 Sort list with alpha order. 714 715 @param e_list: List to sort. 716 ''' 717 return sorted(e_list, key=lambda e: e)
718
719 -def get_dir_size(dirname):
720 ''' 721 Get size of given directory. 722 723 @param dirname: Directory path. 724 @return: Return total size of directory. 725 ''' 726 total_size = 0 727 for root, dirs, files in os.walk(dirname): 728 for filepath in files: 729 total_size += os.path.getsize(os.path.join(root, filepath)) 730 731 return total_size
732 739 757 return wrap 758
759 -def get_font_families():
760 ''' 761 Get all font families in system. 762 763 @return: Return font families list in current system. 764 ''' 765 fontmap = pangocairo.cairo_font_map_get_default() 766 return map (lambda f: f.get_name(), fontmap.list_families())
767
768 -def format_file_size(bytes, precision=2):
769 ''' 770 Returns a humanized string for a given amount of bytes. 771 772 @param bytes: Bytes number to format. 773 @param precision: Number precision. 774 @return: Return a humanized string for a given amount of bytes. 775 ''' 776 bytes = int(bytes) 777 if bytes is 0: 778 return '0B' 779 else: 780 log = math.floor(math.log(bytes, 1024)) 781 quotient = 1024 ** log 782 size = bytes / quotient 783 remainder = bytes % quotient 784 if remainder < 10 ** (-precision): 785 prec = 0 786 else: 787 prec = precision 788 return "%.*f%s" % (prec, 789 size, 790 ['B', 'KB', 'MB', 'GB', 'TB','PB', 'EB', 'ZB', 'YB'] 791 [int(log)])
792
793 -def add_color_stop_rgba(pat, pos, color_info):
794 ''' 795 Add color stop as rgba format. 796 797 @param pat: Pattern. 798 @param pos: Stop position. 799 @param color_info: (color, alpha), color is hex value, alpha value range: [0, 1] 800 ''' 801 # Pick color. 802 (color, alpha) = color_info 803 (r, g, b) = color_hex_to_cairo(color) 804 805 pat.add_color_stop_rgba(pos, r, g, b, alpha)
806
807 -def alpha_color_hex_to_cairo((color, alpha)):
808 ''' 809 Convert alpha color (color, alpha) to cairo color (r, g, b, alpha). 810 811 @param color: Hex color. 812 @param alpha: Alpha value. 813 @return: Return cairo value (red, green, blue, alpha). 814 ''' 815 (r, g, b) = color_hex_to_cairo(color) 816 return (r, g, b, alpha)
817
818 -def color_hex_to_rgb(color):
819 ''' 820 Convert hex color to cairo color (r, g, b). 821 822 @param color: Hex color value. 823 @return: Return cairo value, (red, green, blue) 824 ''' 825 if color[0] == '#': 826 color = color[1:] 827 return (int(color[:2], 16), int(color[2:4], 16), int(color[4:], 16))
828
829 -def color_hex_to_cairo(color):
830 """ 831 Convert a html (hex) RGB value to cairo color. 832 833 @param color: The color to convert. 834 @return: A color in cairo format, (red, green, blue). 835 """ 836 gdk_color = gtk.gdk.color_parse(color) 837 return (gdk_color.red / 65535.0, gdk_color.green / 65535.0, gdk_color.blue / 65535.0)
838
839 -def color_rgb_to_hex(rgb_color):
840 ''' 841 Convert cairo color to hex color. 842 843 @param rgb_color: (red, green, blue) 844 @return: Return hex color. 845 ''' 846 return "#%02X%02X%02X" % rgb_color
847
848 -def color_rgb_to_cairo(color):
849 """ 850 Convert a 8 bit RGB value to cairo color. 851 852 @type color: a triple of integers between 0 and 255 853 @param color: The color to convert. 854 @return: A color in cairo format. 855 """ 856 return (color[0] / 255.0, color[1] / 255.0, color[2] / 255.0) 857
858 -def get_match_parent(widget, match_types):
859 ''' 860 Get parent widget match given type. 861 862 @param widget: Gtk.Widget instance. 863 @param match_types: A list gtk widget types. 864 @return: Return first parent widget match with given types. 865 866 Return None if nothing match. 867 ''' 868 parent = widget.get_parent() 869 if parent == None: 870 return None 871 elif type(parent).__name__ in match_types: 872 return parent 873 else: 874 return get_match_parent(parent, match_types)
875
876 -def widget_fix_cycle_destroy_bug(widget):
877 ''' 878 Fix bug that PyGtk destroys cycle too early. 879 880 @param widget: Gtk.Widget instance. 881 ''' 882 # This code to fix PyGtk bug <<Pygtk destroys cycle too early>>, 883 # The cycle is wrongly freed 884 # by Python's GC because Pygobject does not tell Python that the widget's 885 # wrapper object is referenced by the underlying GObject. As you have 886 # found, in order to break the cycle Python zeros out the callback 887 # closure's captured free variables, which is what causes the "referenced 888 # before assignment" exception. 889 # detail see: https://bugzilla.gnome.org/show_bug.cgi?id=546802 . 890 # 891 # Otherwise, will got error : "NameError: free variable 'self' referenced before assignment in enclosing scope". 892 widget.__dict__
893
894 -def map_value(value_list, get_value_callback):
895 ''' 896 Return value with map list. 897 898 @param value_list: A list to loop. 899 @param get_value_callback: Callback for element in list. 900 @return: Return a new list that every element is result of get_value_callback. 901 ''' 902 if value_list == None: 903 return [] 904 else: 905 return map(get_value_callback, value_list)
906
907 -def get_same_level_widgets(widget):
908 ''' 909 Get same type widgets that in same hierarchy level. 910 911 @param widget: Gtk.Widget instance to search. 912 @return: Return a list that type match given widget at same hierarchy level. 913 ''' 914 parent = widget.get_parent() 915 if parent == None: 916 return [] 917 else: 918 return filter(lambda w:type(w).__name__ == type(widget).__name__, parent.get_children())
919
920 -def mix_list_max(list_a, list_b):
921 ''' 922 Return new list that element is max value between list_a and list_b. 923 924 @param list_a: List a. 925 @param list_b: List b. 926 @return: Return new list that element is max value between two list. 927 928 Return empty list if any input list is empty or two list's length is not same. 929 ''' 930 if list_a == []: 931 return list_b 932 elif list_b == []: 933 return list_a 934 elif len(list_a) == len(list_b): 935 result = [] 936 for (index, item_a) in enumerate(list_a): 937 if item_a > list_b[index]: 938 result.append(item_a) 939 else: 940 result.append(list_b[index]) 941 942 return result 943 else: 944 print "mix_list_max: two list's length not same." 945 return []
946
947 -def unzip(unzip_list):
948 ''' 949 Unzip [(1, 'a'), (2, 'b'), (3, 'c')] to ([1, 2, 3], ['a', 'b', 'c']). 950 951 @param unzip_list: List to unzip. 952 @return: Return new unzip list. 953 ''' 954 first_list, second_list = zip(*unzip_list) 955 return (list(first_list), list(second_list))
956
957 -def is_seriate_list(test_list):
958 ''' 959 Whether is seriate list. 960 961 @param test_list: Test list. 962 @return: Return True is test list is seriate list. 963 ''' 964 for (index, item) in enumerate(test_list): 965 if item != test_list[0] + index: 966 return False 967 968 return True
969
970 -def get_disperse_index(disperse_list, value):
971 ''' 972 Get index in disperse list. 973 974 @param disperse_list: Disperse list. 975 @param value: Match value. 976 @return: Return index in disperse list. 977 ''' 978 for (index, _) in enumerate(disperse_list): 979 start_value = sum(disperse_list[0:index]) 980 end_value = sum(disperse_list[0:index + 1]) 981 if start_value <= value < end_value: 982 return (index, value - start_value) 983 984 # Return last one. 985 return (last_index(disperse_list), disperse_list[-1])
986
987 -def window_is_max(widget):
988 ''' 989 Whether window is maximized. 990 991 @param widget: Gtk.Widget instance. 992 @return: Return True if widget's toplevel window is maximized. 993 ''' 994 toplevel_window = widget.get_toplevel() 995 if toplevel_window.window.get_state() == gtk.gdk.WINDOW_STATE_MAXIMIZED: 996 return True 997 else: 998 return False
999
1000 -def last_index(test_list):
1001 ''' 1002 Return last index of list. 1003 1004 @param test_list: Test list. 1005 @return: Return last index of list. 1006 ''' 1007 return len(test_list) - 1
1008
1009 @contextmanager 1010 -def cairo_state(cr):
1011 ''' 1012 Protected cairo context state for operate cairo safety. 1013 1014 @param cr: Cairo context. 1015 ''' 1016 cr.save() 1017 try: 1018 yield 1019 except Exception, e: 1020 print 'with an cairo error %s' % e 1021 else: 1022 cr.restore()
1023
1024 @contextmanager 1025 -def cairo_disable_antialias(cr):
1026 ''' 1027 Disable cairo antialias temporary. 1028 1029 @param cr: Cairo context. 1030 ''' 1031 # Save antialias. 1032 antialias = cr.get_antialias() 1033 1034 cr.set_antialias(cairo.ANTIALIAS_NONE) 1035 try: 1036 yield 1037 except Exception, e: 1038 print 'with an cairo error %s' % e 1039 else: 1040 # Restore antialias. 1041 cr.set_antialias(antialias)
1042
1043 @contextmanager 1044 -def exec_time():
1045 ''' 1046 Print execute time with given code block. 1047 1048 Usage: 1049 1050 >>> with exec_time(): 1051 >>> # Write any code at here. 1052 >>> # ... 1053 ''' 1054 start_time = time.time() 1055 try: 1056 yield 1057 except Exception, e: 1058 print 'exec_time error %s' % e 1059 else: 1060 print "time: %f" % (time.time() - start_time)
1061
1062 -def remove_timeout_id(callback_id):
1063 ''' 1064 Remove callback id. 1065 1066 @param callback_id: Callback id. 1067 ''' 1068 if callback_id: 1069 gobject.source_remove(callback_id) 1070 callback_id = None
1071
1072 -def remove_signal_id(signal_id):
1073 ''' 1074 Remove signal id. 1075 1076 @param signal_id: Signal id that return by function gobject.connect. 1077 ''' 1078 if signal_id: 1079 (signal_object, signal_handler_id) = signal_id 1080 if signal_object.handler_is_connected(signal_handler_id): 1081 signal_object.disconnect(signal_handler_id) 1082 signal_id = None
1083 1093
1094 -def enable_shadow(widget):
1095 ''' 1096 Whether widget is support composited. 1097 1098 @param widget: Gtk.Widget instance. 1099 @return: Return True if widget is support composited. 1100 ''' 1101 return widget.is_composited()
1102
1103 -def rgb2hsb(r_value, g_value, b_value):
1104 ''' 1105 Convert color from RGB to HSB format. 1106 1107 @param r_value: Red. 1108 @param g_value: Green. 1109 @param b_value: Blue. 1110 @return: Return color with HSB (h, s, b) format. 1111 ''' 1112 r = r_value 1113 g = g_value 1114 b = b_value 1115 1116 max_v = max(r, g, b) 1117 min_v = min(r, g, b) 1118 1119 h = 0.0 1120 1121 if max_v == min_v: 1122 h = 0 1123 elif max_v == r and g >= b: 1124 h = 60 * (g - b) / (max_v - min_v) 1125 elif max_v == r and g < b: 1126 h = 60 * (g - b) / (max_v - min_v) + 360 1127 elif max_v == g: 1128 h = 60 * (b - r) / (max_v - min_v) + 120 1129 elif max_v == b: 1130 h = 60 * (r - g) / (max_v - min_v) + 240 1131 1132 if max_v == 0: 1133 s = 0.0 1134 else: 1135 s = 1.0 - min_v / max_v 1136 1137 b = max_v 1138 1139 return (h, s, b)
1140
1141 -def find_similar_color(search_color):
1142 ''' 1143 Find simliar color match search_color. 1144 1145 @param search_color: Color to search. 1146 @return: Return similar color name and value, (color_name, color_value). 1147 ''' 1148 (search_h, search_s, search_b) = rgb2hsb(*color_hex_to_cairo(search_color)) 1149 hsb_colors = map(lambda name: (name, rgb2hsb(*color_hex_to_cairo(COLOR_NAME_DICT[name]))), SIMILAR_COLOR_SEQUENCE) 1150 1151 # Debug. 1152 # print (search_h, search_s, search_b) 1153 1154 similar_color_name = None 1155 similar_color_value = None 1156 # Return black color if brightness (height) < 0.35 1157 if search_b < 0.35: 1158 similar_color_name = BLACK_COLOR_MAPPED 1159 # Return white color if saturation (radius) < 0.05 1160 elif search_s < 0.05: 1161 similar_color_name = WHITE_COLOR_MAPPED 1162 # Otherwise find nearest color in hsb color space. 1163 else: 1164 min_color_distance = None 1165 for (color_name, (h, s, b)) in hsb_colors: 1166 color_distance = abs(h - search_h) 1167 if min_color_distance == None or color_distance < min_color_distance: 1168 min_color_distance = color_distance 1169 similar_color_name = color_name 1170 1171 similar_color_value = COLOR_NAME_DICT[similar_color_name] 1172 return (similar_color_name, similar_color_value)
1173
1174 -def end_with_suffixs(filepath, suffixs):
1175 ''' 1176 Whether file endswith given suffixs. 1177 1178 @param filepath: Filepath to test. 1179 @param suffixs: A list suffix to match. 1180 @return: Return True if filepath endswith with given suffixs. 1181 ''' 1182 for suffix in suffixs: 1183 if filepath.endswith(suffix): 1184 return True 1185 1186 return False
1187
1188 -def place_center(refer_window, place_window):
1189 ''' 1190 Place place_window in center of refer_window. 1191 1192 @param refer_window: Reference window. 1193 @param place_window: Place window. 1194 ''' 1195 (center_x, center_y) = get_widget_root_coordinate(refer_window, WIDGET_POS_CENTER) 1196 place_window.move( 1197 center_x - place_window.allocation.width / 2, 1198 center_y - place_window.allocation.height / 2 1199 )
1200
1201 -def get_pixbuf_support_foramts():
1202 ''' 1203 Get formats that support by pixbuf. 1204 1205 @return: Return formats that support by pixbuf. 1206 ''' 1207 support_formats = [] 1208 for support_format in gtk.gdk.pixbuf_get_formats(): 1209 support_formats += support_format.get("extensions") 1210 1211 return support_formats
1212
1213 -def get_parent_dir(filepath, level=1):
1214 ''' 1215 Get parent directory with given return level. 1216 1217 @param filepath: Filepath. 1218 @param level: Return level, default is 1 1219 @return: Return parent directory with given return level. 1220 ''' 1221 parent_dir = os.path.realpath(filepath) 1222 1223 while(level > 0): 1224 parent_dir = os.path.dirname(parent_dir) 1225 level -= 1 1226 1227 return parent_dir
1228
1229 -def gdkcolor_to_string(gdkcolor):
1230 ''' 1231 Gdk color to string. 1232 1233 @param gdkcolor: Gdk.Color 1234 @return: Return string of gdk color. 1235 ''' 1236 return "#%0.2X%0.2X%0.2X" % (gdkcolor.red / 256, gdkcolor.green / 256, gdkcolor.blue / 256)
1237
1238 -def is_long(string):
1239 ''' 1240 Is string can convert to long type. 1241 1242 @param string: Test string. 1243 @return: Return True if string can convert to long type. 1244 ''' 1245 if string == "": 1246 return True 1247 1248 try: 1249 long(string) 1250 return True 1251 except ValueError: 1252 return False
1253
1254 -def is_int(string):
1255 ''' 1256 Is string can convert to int type. 1257 1258 @param string: Test string. 1259 @return: Return True if string can convert to int type. 1260 ''' 1261 if string == "": 1262 return True 1263 1264 try: 1265 int(string) 1266 return True 1267 except ValueError: 1268 return False
1269
1270 -def is_float(string):
1271 ''' 1272 Is string can convert to float type. 1273 1274 @param string: Test string. 1275 @return: Return True if string can convert to float type. 1276 ''' 1277 if string == "": 1278 return True 1279 1280 try: 1281 float(string) 1282 return True 1283 except ValueError: 1284 return False
1285
1286 -def is_hex_color(string):
1287 ''' 1288 Is string can convert to hex color type. 1289 1290 @param string: Test string. 1291 @return: Return True if string can convert to hex color type. 1292 ''' 1293 HEX_CHAR = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 1294 "a", "b", "c", "d", "e", "f", 1295 "A", "B", "C", "D", "E", "F", 1296 "#" 1297 ] 1298 1299 if string == "": 1300 return True 1301 else: 1302 for c in string: 1303 if not c in HEX_CHAR: 1304 return False 1305 1306 if string.startswith("#"): 1307 if len(string) > 7: 1308 return False 1309 else: 1310 return True 1311 else: 1312 if len(string) > 6: 1313 return False 1314 else: 1315 return True
1316
1317 -def get_window_shadow_size(window):
1318 ''' 1319 Get window shadow size. 1320 1321 @param window: Test window. 1322 @return: Return shadow size as (width, height), or return (0, 0) if window haven't shadow. 1323 ''' 1324 if "get_shadow_size" in dir(window): 1325 return window.get_shadow_size() 1326 else: 1327 return (0, 0)
1328
1329 -def layout_set_markup(layout, markup):
1330 ''' 1331 Set layout markup. 1332 1333 @param layout: Pango layout. 1334 @param markup: Markup string. 1335 ''' 1336 if "&" in markup or "<" in markup or ">" in markup: 1337 layout.set_markup(markup.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")) 1338 else: 1339 layout.set_markup(markup)
1340
1341 -def get_optimum_pixbuf_from_file(filepath, expect_width, expect_height, cut_middle_area=True):
1342 ''' 1343 Get optimum size pixbuf from file. 1344 1345 @param filepath: Filepath to contain image. 1346 @param expect_width: Expect width. 1347 @param expect_height: Expect height. 1348 @param cut_middle_area: Default cut image with middle area. 1349 @return: Return optimum size pixbuf with expect size. 1350 ''' 1351 pixbuf = gtk.gdk.pixbuf_new_from_file(filepath) 1352 pixbuf_width, pixbuf_height = pixbuf.get_width(), pixbuf.get_height() 1353 if pixbuf_width >= expect_width and pixbuf_height >= expect_height: 1354 if float(pixbuf_width) / pixbuf_height == float(expect_width) / expect_height: 1355 scale_width, scale_height = expect_width, expect_height 1356 elif float(pixbuf_width) / pixbuf_height > float(expect_width) / expect_height: 1357 scale_height = expect_height 1358 scale_width = int(float(pixbuf_width) * expect_height / pixbuf_height) 1359 else: 1360 scale_width = expect_width 1361 scale_height = int(float(pixbuf_height) * expect_width / pixbuf_width) 1362 1363 if cut_middle_area: 1364 subpixbuf_x = (scale_width - expect_width) / 2 1365 subpixbuf_y = (scale_height - expect_height) / 2 1366 else: 1367 subpixbuf_x = 0 1368 subpixbuf_y = 0 1369 1370 return pixbuf.scale_simple( 1371 scale_width, 1372 scale_height, 1373 gtk.gdk.INTERP_BILINEAR).subpixbuf(subpixbuf_x, 1374 subpixbuf_y, 1375 expect_width, 1376 expect_height) 1377 elif pixbuf_width >= expect_width: 1378 scale_width = expect_width 1379 scale_height = int(float(expect_width) * pixbuf_height / pixbuf_width) 1380 1381 if cut_middle_area: 1382 subpixbuf_x = (scale_width - expect_width) / 2 1383 subpixbuf_y = max((scale_height - expect_height) / 2, 0) 1384 else: 1385 subpixbuf_x = 0 1386 subpixbuf_y = 0 1387 1388 return pixbuf.scale_simple( 1389 scale_width, 1390 scale_height, 1391 gtk.gdk.INTERP_BILINEAR).subpixbuf(subpixbuf_x, 1392 subpixbuf_y, 1393 expect_width, 1394 min(expect_height, scale_height)) 1395 elif pixbuf_height >= expect_height: 1396 scale_width = int(float(expect_height) * pixbuf_width / pixbuf_height) 1397 scale_height = expect_height 1398 1399 if cut_middle_area: 1400 subpixbuf_x = max((scale_width - expect_width) / 2, 0) 1401 subpixbuf_y = (scale_height - expect_height) / 2 1402 else: 1403 subpixbuf_x = 0 1404 subpixbuf_y = 0 1405 1406 return pixbuf.scale_simple( 1407 scale_width, 1408 scale_height, 1409 gtk.gdk.INTERP_BILINEAR).subpixbuf(subpixbuf_x, 1410 subpixbuf_y, 1411 min(expect_width, scale_width), 1412 expect_height) 1413 else: 1414 return pixbuf
1415
1416 -def unique_print(text):
1417 ''' 1418 Unique print, generic for test code. 1419 1420 @param text: Test text. 1421 ''' 1422 print "%s: %s" % (time.time(), text)
1423
1424 -def check_connect_by_port(port, retry_times=6, sleep_time=0.5):
1425 """ 1426 Check connect has active with given port. 1427 1428 @param port: Test port. 1429 @param retry_times: Retry times. 1430 @param sleep_time: Sleep time between retry, in seconds. 1431 @return: Return True if given port is active. 1432 """ 1433 ret_val = False 1434 test_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 1435 retry_time = 0 1436 while (True): 1437 try: 1438 test_socket.connect(("localhost", port)) 1439 ret_val = True 1440 break 1441 except socket.error: 1442 time.sleep(sleep_time) 1443 retry_time += 1 1444 if retry_time >= retry_times: 1445 break 1446 else: 1447 continue 1448 return ret_val
1449
1450 -def is_network_connected():
1451 ''' 1452 Is network connected, if nothing in file `/proc/net/arp`, network is disconnected. 1453 1454 @return: Return True if network is connected. 1455 ''' 1456 return len(filter(lambda line: line != '', open("/proc/net/arp", "r").read().split("\n")) )> 1
1457