summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/ui/crumbs/hobwidget.py
diff options
context:
space:
mode:
authorJoshua Lock <josh@linux.intel.com>2012-04-12 19:43:12 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2012-05-20 09:24:25 +0100
commit44a40f7a569ac583a949a088f14f97f66b19af4f (patch)
tree582da5d407e3e54053c11e4318bff681815197d2 /bitbake/lib/bb/ui/crumbs/hobwidget.py
parent881b81f2661f264795bfc9d10895a0675220369f (diff)
downloadpoky-44a40f7a569ac583a949a088f14f97f66b19af4f.tar.gz
lib/bb/ui/crumbs/: replace custom HobNotebook
The custom HobNotebook widget was implemented to address perceived deficiencies in the gtk.Notebook API. Recent inspection reveals that the API is capable of all that Hob requires of it and therefore maintaining a custom class to provide similar functionality does not make sense. Addresses [YOCTO #2276] (Bitbake rev: e683caa9863bbb52480346669806f22173629a5e) Signed-off-by: Joshua Lock <josh@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb/ui/crumbs/hobwidget.py')
-rw-r--r--bitbake/lib/bb/ui/crumbs/hobwidget.py499
1 files changed, 114 insertions, 385 deletions
diff --git a/bitbake/lib/bb/ui/crumbs/hobwidget.py b/bitbake/lib/bb/ui/crumbs/hobwidget.py
index 39428270a8..0419d27db1 100644
--- a/bitbake/lib/bb/ui/crumbs/hobwidget.py
+++ b/bitbake/lib/bb/ui/crumbs/hobwidget.py
@@ -23,6 +23,7 @@ import os
23import os.path 23import os.path
24import sys 24import sys
25import pango, pangocairo 25import pango, pangocairo
26import cairo
26import math 27import math
27 28
28from bb.ui.crumbs.hobcolor import HobColors 29from bb.ui.crumbs.hobcolor import HobColors
@@ -396,363 +397,130 @@ class HobInfoButton(gtk.EventBox):
396 def mouse_out_cb(self, widget, event): 397 def mouse_out_cb(self, widget, event):
397 self.image.set_from_file(hic.ICON_INFO_DISPLAY_FILE) 398 self.image.set_from_file(hic.ICON_INFO_DISPLAY_FILE)
398 399
399class HobTabBar(gtk.DrawingArea): 400class HobIndicator(gtk.DrawingArea):
400 __gsignals__ = { 401 def __init__(self, count):
401 "blank-area-changed" : (gobject.SIGNAL_RUN_LAST,
402 gobject.TYPE_NONE,
403 (gobject.TYPE_INT,
404 gobject.TYPE_INT,
405 gobject.TYPE_INT,
406 gobject.TYPE_INT,)),
407
408 "tab-switched" : (gobject.SIGNAL_RUN_LAST,
409 gobject.TYPE_NONE,
410 (gobject.TYPE_INT,)),
411 }
412
413 def __init__(self):
414 gtk.DrawingArea.__init__(self) 402 gtk.DrawingArea.__init__(self)
415 self.children = []
416
417 self.tab_width = 140
418 self.tab_height = 52
419 self.tab_x = 10
420 self.tab_y = 0
421
422 self.width = 500
423 self.height = 53
424 self.tab_w_ratio = 140 * 1.0/500
425 self.tab_h_ratio = 52 * 1.0/53
426 self.set_size_request(self.width, self.height)
427
428 self.current_child = None
429 self.font = self.get_style().font_desc
430 self.font.set_size(pango.SCALE * 13)
431 self.update_children_text_layout_and_bg_color()
432
433 self.blank_rectangle = None
434 self.tab_pressed = False
435
436 self.set_property('can-focus', True)
437 self.set_events(gtk.gdk.EXPOSURE_MASK | gtk.gdk.POINTER_MOTION_MASK |
438 gtk.gdk.BUTTON1_MOTION_MASK | gtk.gdk.BUTTON_PRESS_MASK |
439 gtk.gdk.BUTTON_RELEASE_MASK)
440
441 self.connect("expose-event", self.on_draw)
442 self.connect("button-press-event", self.button_pressed_cb)
443 self.connect("button-release-event", self.button_released_cb)
444 self.connect("query-tooltip", self.query_tooltip_cb)
445 self.show_all()
446
447 def button_released_cb(self, widget, event):
448 self.tab_pressed = False
449 self.queue_draw()
450
451 def button_pressed_cb(self, widget, event):
452 if event.type == gtk.gdk._2BUTTON_PRESS:
453 return
454
455 result = False
456 if self.is_focus() or event.type == gtk.gdk.BUTTON_PRESS:
457 x, y = event.get_coords()
458 # check which tab be clicked
459 for child in self.children:
460 if (child["x"] < x) and (x < child["x"] + self.tab_width) \
461 and (child["y"] < y) and (y < child["y"] + self.tab_height):
462 self.current_child = child
463 result = True
464 self.grab_focus()
465 break
466
467 # check the blank area is focus in or not
468 if (self.blank_rectangle) and (self.blank_rectangle.x > 0) and (self.blank_rectangle.y > 0):
469 if (self.blank_rectangle.x < x) and (x < self.blank_rectangle.x + self.blank_rectangle.width) \
470 and (self.blank_rectangle.y < y) and (y < self.blank_rectangle.y + self.blank_rectangle.height):
471 self.grab_focus()
472
473 if result == True:
474 page = self.current_child["toggled_page"]
475 self.emit("tab-switched", page)
476 self.tab_pressed = True
477 self.queue_draw()
478
479 def update_children_size(self):
480 # calculate the size of tabs
481 self.tab_width = int(self.width * self.tab_w_ratio)
482 self.tab_height = int(self.height * self.tab_h_ratio)
483 for i, child in enumerate(self.children):
484 child["x"] = self.tab_x + i * self.tab_width
485 child["y"] = self.tab_y
486
487 if self.blank_rectangle:
488 self.resize_blank_rectangle()
489
490 def resize_blank_rectangle(self):
491 width = self.width - self.tab_width * len(self.children) - self.tab_x
492 x = self.tab_x + self.tab_width * len(self.children)
493 hpadding = vpadding = 5
494 self.blank_rectangle = self.set_blank_size(x + hpadding, self.tab_y + vpadding,
495 width - 2 * hpadding, self.tab_height - 2 * vpadding)
496
497 def update_children_text_layout_and_bg_color(self):
498 style = self.get_style().copy()
499 color = style.base[gtk.STATE_NORMAL]
500 for child in self.children:
501 pangolayout = self.create_pango_layout(child["title"])
502 pangolayout.set_font_description(self.font)
503 child["title_layout"] = pangolayout
504 child["r"] = color.red
505 child["g"] = color.green
506 child["b"] = color.blue
507
508 def append_tab_child(self, title, page, tooltip=""):
509 num = len(self.children) + 1
510 self.tab_width = self.tab_width * len(self.children) / num
511
512 i = 0
513 for i, child in enumerate(self.children):
514 child["x"] = self.tab_x + i * self.tab_width
515 i += 1
516
517 x = self.tab_x + i * self.tab_width
518 y = self.tab_y
519 pangolayout = self.create_pango_layout(title)
520 pangolayout.set_font_description(self.font)
521 color = self.style.base[gtk.STATE_NORMAL]
522 new_one = {
523 "x" : x,
524 "y" : y,
525 "r" : color.red,
526 "g" : color.green,
527 "b" : color.blue,
528 "title_layout" : pangolayout,
529 "toggled_page" : page,
530 "title" : title,
531 "indicator_show" : False,
532 "indicator_number" : 0,
533 "tooltip_markup" : tooltip,
534 }
535 self.children.append(new_one)
536 if tooltip and (not self.props.has_tooltip):
537 self.props.has_tooltip = True
538 # set the default current child
539 if not self.current_child:
540 self.current_child = new_one
541
542 def on_draw(self, widget, event):
543 cr = widget.window.cairo_create()
544
545 self.width = self.allocation.width
546 self.height = self.allocation.height
547
548 self.update_children_size()
549
550 self.draw_background(cr)
551 self.draw_toggled_tab(cr)
552
553 for child in self.children:
554 if child["indicator_show"] == True:
555 self.draw_indicator(cr, child)
556
557 self.draw_tab_text(cr)
558
559 def draw_background(self, cr):
560 style = self.get_style()
561
562 if self.is_focus():
563 cr.set_source_color(style.base[gtk.STATE_SELECTED])
564 else:
565 cr.set_source_color(style.base[gtk.STATE_NORMAL])
566
567 y = 6
568 h = self.height - 6 - 1
569 gap = 1
570
571 w = self.children[0]["x"]
572 cr.set_source_color(gtk.gdk.color_parse(HobColors.GRAY))
573 cr.rectangle(0, y, w - gap, h) # start rectangle
574 cr.fill()
575
576 cr.set_source_color(style.base[gtk.STATE_NORMAL])
577 cr.rectangle(w - gap, y, w, h) #first gap
578 cr.fill()
579 403
580 w = self.tab_width 404 # We want to composite the transparent indicator onto the parent
581 for child in self.children: 405 # HBox
582 x = child["x"] 406 screen = self.get_screen()
583 cr.set_source_color(gtk.gdk.color_parse(HobColors.GRAY)) 407 rgba = screen.get_rgba_colormap()
584 cr.rectangle(x, y, w - gap, h) # tab rectangle 408 self.set_colormap(rgba)
585 cr.fill() 409 self.set_app_paintable(True)
586 cr.set_source_color(style.base[gtk.STATE_NORMAL]) 410 self.set_size_request(38,38)
587 cr.rectangle(x + w - gap, y, w, h) # gap 411 # We need to pass through button clicks
588 cr.fill() 412 self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK)
589 413
590 cr.set_source_color(gtk.gdk.color_parse(HobColors.GRAY)) 414 self.connect('expose-event', self.expose)
591 cr.rectangle(x + w, y, self.width - x - w, h) # last rectangle 415 self.connect_after('realize', self.composite)
592 cr.fill() 416
593 417 self.count = count
594 def draw_tab_text(self, cr): 418 self.color = HobColors.GRAY
595 style = self.get_style() 419
596 420 def composite(self, widget):
597 for child in self.children: 421 # This property must be set after the widget has been realised
598 pangolayout = child["title_layout"] 422 self.window.set_composited(True)
599 if pangolayout: 423
600 fontw, fonth = pangolayout.get_pixel_size() 424 def expose(self, widget, event):
601 # center pos 425 # Transparent background
602 off_x = (self.tab_width - fontw) / 2 426 ctx = widget.window.cairo_create()
603 off_y = (self.tab_height - fonth) / 2 427 ctx.set_operator(cairo.OPERATOR_CLEAR)
604 x = child["x"] + off_x 428 region = gtk.gdk.region_rectangle(event.area)
605 y = child["y"] + off_y 429
606 if not child == self.current_child: 430 ctx.region(region)
607 self.window.draw_layout(self.style.fg_gc[gtk.STATE_NORMAL], int(x), int(y), pangolayout, gtk.gdk.Color(HobColors.WHITE)) 431 ctx.fill()
608 else: 432
609 self.window.draw_layout(self.style.fg_gc[gtk.STATE_NORMAL], int(x), int(y), pangolayout) 433 if self.count and self.count > 0:
610 434 w = self.allocation.width
611 def draw_toggled_tab(self, cr): 435 h = self.allocation.height
612 if not self.current_child: 436
613 return 437 ctx.set_operator(cairo.OPERATOR_OVER)
614 x = self.current_child["x"] 438 ctx.set_source_color(gtk.gdk.color_parse(self.color))
615 y = self.current_child["y"] 439 ctx.translate(w/2, h/2)
616 width = self.tab_width 440 ctx.arc(1, 1, min(w,h)/2 - 2, 0, 2*math.pi)
617 height = self.tab_height 441 ctx.fill_preserve()
618 style = self.get_style() 442
619 color = style.base[gtk.STATE_NORMAL] 443 layout = self.create_pango_layout(str(self.count))
620 444 textw, texth = layout.get_pixel_size()
621 r = height / 10 445 x = (w/2)-(textw/2) + 1
622 if self.tab_pressed == True: 446 y = (h/2) - (texth/2) + 1
623 for xoff, yoff, c1, c2 in [(1, 0, HobColors.SLIGHT_DARK, HobColors.DARK), (2, 0, HobColors.GRAY, HobColors.LIGHT_GRAY)]: 447 ctx.move_to(x, y)
624 cr.set_source_color(gtk.gdk.color_parse(c1)) 448 self.window.draw_layout(self.style.fg_gc[gtk.STATE_NORMAL], int(x), int(y), layout)
625 cr.move_to(x + xoff, y + height + yoff) 449
626 cr.line_to(x + xoff, r + yoff) 450 def set_count(self, count):
627 cr.arc(x + r + xoff, y + r + yoff, r, math.pi, 1.5*math.pi) 451 self.count = count
628 cr.move_to(x + r + xoff, y + yoff) 452
629 cr.line_to(x + width - r + xoff, y + yoff) 453 def set_active(self, active):
630 cr.arc(x + width - r + xoff, y + r + yoff, r, 1.5*math.pi, 2*math.pi) 454 if active:
631 cr.stroke() 455 self.color = HobColors.DEEP_RED
632 cr.set_source_color(gtk.gdk.color_parse(c2))
633 cr.move_to(x + width + xoff, r + yoff)
634 cr.line_to(x + width + xoff, y + height + yoff)
635 cr.line_to(x + xoff, y + height + yoff)
636 cr.stroke()
637 x = x + 2
638 y = y + 2
639 cr.set_source_rgba(color.red, color.green, color.blue, 1)
640 cr.move_to(x + r, y)
641 cr.line_to(x + width - r , y)
642 cr.arc(x + width - r, y + r, r, 1.5*math.pi, 2*math.pi)
643 cr.move_to(x + width, r)
644 cr.line_to(x + width, y + height)
645 cr.line_to(x, y + height)
646 cr.line_to(x, r)
647 cr.arc(x + r, y + r, r, math.pi, 1.5*math.pi)
648 cr.fill()
649
650 def draw_indicator(self, cr, child):
651 text = ("%d" % child["indicator_number"])
652 layout = self.create_pango_layout(text)
653 layout.set_font_description(self.font)
654 textw, texth = layout.get_pixel_size()
655 # draw the back round area
656 tab_x = child["x"]
657 tab_y = child["y"]
658 dest_w = int(32 * self.tab_w_ratio)
659 dest_h = int(32 * self.tab_h_ratio)
660 if dest_h < self.tab_height:
661 dest_w = dest_h
662 # x position is offset(tab_width*3/4 - icon_width/2) + start_pos(tab_x)
663 x = tab_x + self.tab_width * 3/4 - dest_w/2
664 y = tab_y + self.tab_height/2 - dest_h/2
665
666 r = min(dest_w, dest_h)/2
667 if not child == self.current_child:
668 color = cr.set_source_color(gtk.gdk.color_parse(HobColors.DEEP_RED))
669 else:
670 color = cr.set_source_color(gtk.gdk.color_parse(HobColors.GRAY))
671 # check round back area can contain the text or not
672 back_round_can_contain_width = float(2 * r * 0.707)
673 if float(textw) > back_round_can_contain_width:
674 xoff = (textw - int(back_round_can_contain_width)) / 2
675 cr.move_to(x + r - xoff, y + r + r)
676 cr.arc((x + r - xoff), (y + r), r, 0.5*math.pi, 1.5*math.pi)
677 cr.fill() # left half round
678 cr.rectangle((x + r - xoff), y, 2 * xoff, 2 * r)
679 cr.fill() # center rectangle
680 cr.arc((x + r + xoff), (y + r), r, 1.5*math.pi, 0.5*math.pi)
681 cr.fill() # right half round
682 else: 456 else:
683 cr.arc((x + r), (y + r), r, 0, 2*math.pi) 457 self.color = HobColors.GRAY
684 cr.fill() 458
685 # draw the number text 459class HobTabLabel(gtk.HBox):
686 x = x + (dest_w/2)-(textw/2) 460 def __init__(self, text, count=0):
687 y = y + (dest_h/2) - (texth/2) 461 gtk.HBox.__init__(self, False, 0)
688 cr.move_to(x, y) 462 self.indicator = HobIndicator(count)
689 self.window.draw_layout(self.style.fg_gc[gtk.STATE_NORMAL], int(x), int(y), layout, gtk.gdk.Color(HobColors.WHITE)) 463 self.indicator.show()
690 464 self.pack_end(self.indicator, False, False)
691 def show_indicator_icon(self, child, number): 465 self.lbl = gtk.Label(text)
692 child["indicator_show"] = True 466 self.lbl.set_alignment(0.0, 0.5)
693 child["indicator_number"] = number 467 self.lbl.show()
694 self.queue_draw() 468 self.pack_end(self.lbl, True, True, 6)
695 469 self.connect_after('expose-event', self.expose_event)
696 def hide_indicator_icon(self, child): 470
697 child["indicator_show"] = False 471 def expose_event(self, widget, event):
698 self.queue_draw() 472 # Composite the child indicator onto the Box
699 473 child = self.indicator
700 def set_blank_size(self, x, y, w, h): 474 ctx = widget.window.cairo_create()
701 if not self.blank_rectangle or self.blank_rectangle.x != x or self.blank_rectangle.width != w: 475
702 self.emit("blank-area-changed", x, y, w, h) 476 ctx.set_source_pixmap(child.window, child.allocation.x, child.allocation.y)
703 477
704 return gtk.gdk.Rectangle(x, y, w, h) 478 region = gtk.gdk.region_rectangle(child.allocation)
705 479 r = gtk.gdk.region_rectangle(event.area)
706 def query_tooltip_cb(self, widget, x, y, keyboardtip, tooltip): 480 region.intersect(r)
707 if keyboardtip or (not tooltip): 481 ctx.region(region)
708 return False 482 ctx.clip()
709 # check which tab be clicked 483
710 for child in self.children: 484 ctx.paint()
711 if (child["x"] < x) and (x < child["x"] + self.tab_width) \
712 and (child["y"] < y) and (y < child["y"] + self.tab_height):
713 tooltip.set_markup(child["tooltip_markup"])
714 return True
715 485
716 return False 486 return False
717 487
718class HobNotebook(gtk.VBox): 488 def set_count(self, count):
489 self.indicator.set_count(count)
719 490
720 def __init__(self): 491 def set_active(self, active=True):
721 gtk.VBox.__init__(self, False, 0) 492 self.indicator.set_active(active)
722 493
723 self.notebook = gtk.Notebook() 494class HobNotebook(gtk.Notebook):
724 self.notebook.set_property('homogeneous', True) 495 def __init__(self):
725 self.notebook.set_property('show-tabs', False) 496 gtk.Notebook.__init__(self)
497 self.set_property('homogeneous', True)
726 498
727 self.tabbar = HobTabBar() 499 self.pages = []
728 self.tabbar.connect("tab-switched", self.tab_switched_cb)
729 self.notebook.connect("page-added", self.page_added_cb)
730 self.notebook.connect("page-removed", self.page_removed_cb)
731 500
732 self.search = None 501 self.search = None
733 self.search_name = "" 502 self.search_name = ""
734 503
735 self.tb = gtk.Table(1, 100, False) 504 self.connect("switch-page", self.page_changed_cb)
736 self.hbox= gtk.HBox(False, 0)
737 self.hbox.pack_start(self.tabbar, True, True)
738 self.tb.attach(self.hbox, 0, 100, 0, 1)
739
740 self.pack_start(self.tb, False, False)
741 self.pack_start(self.notebook)
742 505
743 self.show_all() 506 self.show_all()
744 507
745 def append_page(self, child, tab_label): 508 def page_changed_cb(self, nb, page, page_num):
746 self.notebook.set_current_page(self.notebook.append_page(child, tab_label)) 509 for p, lbl in enumerate(self.pages):
747 510 if p == page_num:
748 def set_entry(self, name="Search:"): 511 lbl.set_active()
749 for child in self.tb.get_children(): 512 else:
750 if child: 513 lbl.set_active(False)
751 self.tb.remove(child)
752 514
753 hbox_entry = gtk.HBox(False, 0) 515 def append_page(self, child, tab_label, tab_tooltip=None):
754 hbox_entry.show() 516 label = HobTabLabel(tab_label)
517 if tab_tooltip:
518 label.set_tooltip_text(tab_tooltip)
519 label.set_active(False)
520 self.pages.append(label)
521 gtk.Notebook.append_page(self, child, label)
755 522
523 def set_entry(self, name="Search:"):
756 self.search = gtk.Entry() 524 self.search = gtk.Entry()
757 self.search_name = name 525 self.search_name = name
758 style = self.search.get_style() 526 style = self.search.get_style()
@@ -763,59 +531,20 @@ class HobNotebook(gtk.VBox):
763 self.search.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY, gtk.STOCK_CLEAR) 531 self.search.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY, gtk.STOCK_CLEAR)
764 self.search.connect("icon-release", self.set_search_entry_clear_cb) 532 self.search.connect("icon-release", self.set_search_entry_clear_cb)
765 self.search.show() 533 self.search.show()
766 self.align = gtk.Alignment(xalign=1.0, yalign=0.7)
767 self.align.add(self.search)
768 self.align.show()
769 hbox_entry.pack_end(self.align, False, False)
770 self.tabbar.resize_blank_rectangle()
771 534
772 self.tb.attach(hbox_entry, 75, 100, 0, 1, xpadding=5)
773 self.tb.attach(self.hbox, 0, 100, 0, 1)
774
775 self.tabbar.connect("blank-area-changed", self.blank_area_resize_cb)
776 self.search.connect("focus-in-event", self.set_search_entry_editable_cb) 535 self.search.connect("focus-in-event", self.set_search_entry_editable_cb)
777 self.search.connect("focus-out-event", self.set_search_entry_reset_cb) 536 self.search.connect("focus-out-event", self.set_search_entry_reset_cb)
778 537 self.set_action_widget(self.search, gtk.PACK_END)
779 self.tb.show()
780 538
781 def show_indicator_icon(self, title, number): 539 def show_indicator_icon(self, title, number):
782 for child in self.tabbar.children: 540 for child in self.pages:
783 if child["toggled_page"] == -1: 541 if child.lbl.get_label() == title:
784 continue 542 child.set_count(number)
785 if child["title"] == title:
786 self.tabbar.show_indicator_icon(child, number)
787 543
788 def hide_indicator_icon(self, title): 544 def hide_indicator_icon(self, title):
789 for child in self.tabbar.children: 545 for child in self.pages:
790 if child["toggled_page"] == -1: 546 if child.lbl.get_label() == title:
791 continue 547 child.set_count(0)
792 if child["title"] == title:
793 self.tabbar.hide_indicator_icon(child)
794
795 def tab_switched_cb(self, widget, page):
796 self.notebook.set_current_page(page)
797
798 def page_added_cb(self, notebook, notebook_child, page):
799 if not notebook:
800 return
801 title = notebook.get_tab_label_text(notebook_child)
802 label = notebook.get_tab_label(notebook_child)
803 tooltip_markup = label.get_tooltip_markup()
804 if not title:
805 return
806 for child in self.tabbar.children:
807 if child["title"] == title:
808 child["toggled_page"] = page
809 return
810 self.tabbar.append_tab_child(title, page, tooltip_markup)
811
812 def page_removed_cb(self, notebook, notebook_child, page, title=""):
813 for child in self.tabbar.children:
814 if child["title"] == title:
815 child["toggled_page"] = -1
816
817 def blank_area_resize_cb(self, widget, request_x, request_y, request_width, request_height):
818 self.search.set_size_request(request_width, request_height)
819 548
820 def set_search_entry_editable_cb(self, search, event): 549 def set_search_entry_editable_cb(self, search, event):
821 search.set_editable(True) 550 search.set_editable(True)