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>
This commit is contained in:
Joshua Lock 2012-04-12 19:43:12 +00:00 committed by Richard Purdie
parent 881b81f266
commit 44a40f7a56
4 changed files with 104 additions and 379 deletions

View File

@ -144,7 +144,7 @@ class BuildDetailsPage (HobPage):
self.scrolled_view_config = gtk.ScrolledWindow () self.scrolled_view_config = gtk.ScrolledWindow ()
self.scrolled_view_config.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) self.scrolled_view_config.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
self.scrolled_view_config.add(self.config_tv) self.scrolled_view_config.add(self.config_tv)
self.notebook.append_page(self.scrolled_view_config, gtk.Label("Build configuration")) self.notebook.append_page(self.scrolled_view_config, "Build configuration")
self.failure_tv = BuildFailureTreeView() self.failure_tv = BuildFailureTreeView()
self.failure_model = self.builder.handler.build.model.failure_model() self.failure_model = self.builder.handler.build.model.failure_model()
@ -152,14 +152,14 @@ class BuildDetailsPage (HobPage):
self.scrolled_view_failure = gtk.ScrolledWindow () self.scrolled_view_failure = gtk.ScrolledWindow ()
self.scrolled_view_failure.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) self.scrolled_view_failure.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
self.scrolled_view_failure.add(self.failure_tv) self.scrolled_view_failure.add(self.failure_tv)
self.notebook.append_page(self.scrolled_view_failure, gtk.Label("Issues")) self.notebook.append_page(self.scrolled_view_failure, "Issues")
self.build_tv = RunningBuildTreeView(readonly=True, hob=True) self.build_tv = RunningBuildTreeView(readonly=True, hob=True)
self.build_tv.set_model(self.builder.handler.build.model) self.build_tv.set_model(self.builder.handler.build.model)
self.scrolled_view_build = gtk.ScrolledWindow () self.scrolled_view_build = gtk.ScrolledWindow ()
self.scrolled_view_build.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) self.scrolled_view_build.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
self.scrolled_view_build.add(self.build_tv) self.scrolled_view_build.add(self.build_tv)
self.notebook.append_page(self.scrolled_view_build, gtk.Label("Log")) self.notebook.append_page(self.scrolled_view_build, "Log")
self.builder.handler.build.model.connect_after("row-changed", self.scroll_to_present_row, self.scrolled_view_build.get_vadjustment(), self.build_tv) self.builder.handler.build.model.connect_after("row-changed", self.scroll_to_present_row, self.scrolled_view_build.get_vadjustment(), self.build_tv)

View File

@ -23,6 +23,7 @@ import os
import os.path import os.path
import sys import sys
import pango, pangocairo import pango, pangocairo
import cairo
import math import math
from bb.ui.crumbs.hobcolor import HobColors from bb.ui.crumbs.hobcolor import HobColors
@ -396,363 +397,130 @@ class HobInfoButton(gtk.EventBox):
def mouse_out_cb(self, widget, event): def mouse_out_cb(self, widget, event):
self.image.set_from_file(hic.ICON_INFO_DISPLAY_FILE) self.image.set_from_file(hic.ICON_INFO_DISPLAY_FILE)
class HobTabBar(gtk.DrawingArea): class HobIndicator(gtk.DrawingArea):
__gsignals__ = { def __init__(self, count):
"blank-area-changed" : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_INT,
gobject.TYPE_INT,
gobject.TYPE_INT,
gobject.TYPE_INT,)),
"tab-switched" : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_INT,)),
}
def __init__(self):
gtk.DrawingArea.__init__(self) gtk.DrawingArea.__init__(self)
self.children = []
self.tab_width = 140 # We want to composite the transparent indicator onto the parent
self.tab_height = 52 # HBox
self.tab_x = 10 screen = self.get_screen()
self.tab_y = 0 rgba = screen.get_rgba_colormap()
self.set_colormap(rgba)
self.set_app_paintable(True)
self.set_size_request(38,38)
# We need to pass through button clicks
self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK)
self.width = 500 self.connect('expose-event', self.expose)
self.height = 53 self.connect_after('realize', self.composite)
self.tab_w_ratio = 140 * 1.0/500
self.tab_h_ratio = 52 * 1.0/53
self.set_size_request(self.width, self.height)
self.current_child = None self.count = count
self.font = self.get_style().font_desc self.color = HobColors.GRAY
self.font.set_size(pango.SCALE * 13)
self.update_children_text_layout_and_bg_color()
self.blank_rectangle = None def composite(self, widget):
self.tab_pressed = False # This property must be set after the widget has been realised
self.window.set_composited(True)
self.set_property('can-focus', True) def expose(self, widget, event):
self.set_events(gtk.gdk.EXPOSURE_MASK | gtk.gdk.POINTER_MOTION_MASK | # Transparent background
gtk.gdk.BUTTON1_MOTION_MASK | gtk.gdk.BUTTON_PRESS_MASK | ctx = widget.window.cairo_create()
gtk.gdk.BUTTON_RELEASE_MASK) ctx.set_operator(cairo.OPERATOR_CLEAR)
region = gtk.gdk.region_rectangle(event.area)
self.connect("expose-event", self.on_draw) ctx.region(region)
self.connect("button-press-event", self.button_pressed_cb) ctx.fill()
self.connect("button-release-event", self.button_released_cb)
self.connect("query-tooltip", self.query_tooltip_cb)
self.show_all()
def button_released_cb(self, widget, event): if self.count and self.count > 0:
self.tab_pressed = False w = self.allocation.width
self.queue_draw() h = self.allocation.height
def button_pressed_cb(self, widget, event): ctx.set_operator(cairo.OPERATOR_OVER)
if event.type == gtk.gdk._2BUTTON_PRESS: ctx.set_source_color(gtk.gdk.color_parse(self.color))
return ctx.translate(w/2, h/2)
ctx.arc(1, 1, min(w,h)/2 - 2, 0, 2*math.pi)
ctx.fill_preserve()
result = False layout = self.create_pango_layout(str(self.count))
if self.is_focus() or event.type == gtk.gdk.BUTTON_PRESS: textw, texth = layout.get_pixel_size()
x, y = event.get_coords() x = (w/2)-(textw/2) + 1
# check which tab be clicked y = (h/2) - (texth/2) + 1
for child in self.children: ctx.move_to(x, y)
if (child["x"] < x) and (x < child["x"] + self.tab_width) \ self.window.draw_layout(self.style.fg_gc[gtk.STATE_NORMAL], int(x), int(y), layout)
and (child["y"] < y) and (y < child["y"] + self.tab_height):
self.current_child = child
result = True
self.grab_focus()
break
# check the blank area is focus in or not def set_count(self, count):
if (self.blank_rectangle) and (self.blank_rectangle.x > 0) and (self.blank_rectangle.y > 0): self.count = count
if (self.blank_rectangle.x < x) and (x < self.blank_rectangle.x + self.blank_rectangle.width) \
and (self.blank_rectangle.y < y) and (y < self.blank_rectangle.y + self.blank_rectangle.height):
self.grab_focus()
if result == True: def set_active(self, active):
page = self.current_child["toggled_page"] if active:
self.emit("tab-switched", page) self.color = HobColors.DEEP_RED
self.tab_pressed = True
self.queue_draw()
def update_children_size(self):
# calculate the size of tabs
self.tab_width = int(self.width * self.tab_w_ratio)
self.tab_height = int(self.height * self.tab_h_ratio)
for i, child in enumerate(self.children):
child["x"] = self.tab_x + i * self.tab_width
child["y"] = self.tab_y
if self.blank_rectangle:
self.resize_blank_rectangle()
def resize_blank_rectangle(self):
width = self.width - self.tab_width * len(self.children) - self.tab_x
x = self.tab_x + self.tab_width * len(self.children)
hpadding = vpadding = 5
self.blank_rectangle = self.set_blank_size(x + hpadding, self.tab_y + vpadding,
width - 2 * hpadding, self.tab_height - 2 * vpadding)
def update_children_text_layout_and_bg_color(self):
style = self.get_style().copy()
color = style.base[gtk.STATE_NORMAL]
for child in self.children:
pangolayout = self.create_pango_layout(child["title"])
pangolayout.set_font_description(self.font)
child["title_layout"] = pangolayout
child["r"] = color.red
child["g"] = color.green
child["b"] = color.blue
def append_tab_child(self, title, page, tooltip=""):
num = len(self.children) + 1
self.tab_width = self.tab_width * len(self.children) / num
i = 0
for i, child in enumerate(self.children):
child["x"] = self.tab_x + i * self.tab_width
i += 1
x = self.tab_x + i * self.tab_width
y = self.tab_y
pangolayout = self.create_pango_layout(title)
pangolayout.set_font_description(self.font)
color = self.style.base[gtk.STATE_NORMAL]
new_one = {
"x" : x,
"y" : y,
"r" : color.red,
"g" : color.green,
"b" : color.blue,
"title_layout" : pangolayout,
"toggled_page" : page,
"title" : title,
"indicator_show" : False,
"indicator_number" : 0,
"tooltip_markup" : tooltip,
}
self.children.append(new_one)
if tooltip and (not self.props.has_tooltip):
self.props.has_tooltip = True
# set the default current child
if not self.current_child:
self.current_child = new_one
def on_draw(self, widget, event):
cr = widget.window.cairo_create()
self.width = self.allocation.width
self.height = self.allocation.height
self.update_children_size()
self.draw_background(cr)
self.draw_toggled_tab(cr)
for child in self.children:
if child["indicator_show"] == True:
self.draw_indicator(cr, child)
self.draw_tab_text(cr)
def draw_background(self, cr):
style = self.get_style()
if self.is_focus():
cr.set_source_color(style.base[gtk.STATE_SELECTED])
else: else:
cr.set_source_color(style.base[gtk.STATE_NORMAL]) self.color = HobColors.GRAY
y = 6 class HobTabLabel(gtk.HBox):
h = self.height - 6 - 1 def __init__(self, text, count=0):
gap = 1 gtk.HBox.__init__(self, False, 0)
self.indicator = HobIndicator(count)
self.indicator.show()
self.pack_end(self.indicator, False, False)
self.lbl = gtk.Label(text)
self.lbl.set_alignment(0.0, 0.5)
self.lbl.show()
self.pack_end(self.lbl, True, True, 6)
self.connect_after('expose-event', self.expose_event)
w = self.children[0]["x"] def expose_event(self, widget, event):
cr.set_source_color(gtk.gdk.color_parse(HobColors.GRAY)) # Composite the child indicator onto the Box
cr.rectangle(0, y, w - gap, h) # start rectangle child = self.indicator
cr.fill() ctx = widget.window.cairo_create()
cr.set_source_color(style.base[gtk.STATE_NORMAL]) ctx.set_source_pixmap(child.window, child.allocation.x, child.allocation.y)
cr.rectangle(w - gap, y, w, h) #first gap
cr.fill()
w = self.tab_width region = gtk.gdk.region_rectangle(child.allocation)
for child in self.children: r = gtk.gdk.region_rectangle(event.area)
x = child["x"] region.intersect(r)
cr.set_source_color(gtk.gdk.color_parse(HobColors.GRAY)) ctx.region(region)
cr.rectangle(x, y, w - gap, h) # tab rectangle ctx.clip()
cr.fill()
cr.set_source_color(style.base[gtk.STATE_NORMAL])
cr.rectangle(x + w - gap, y, w, h) # gap
cr.fill()
cr.set_source_color(gtk.gdk.color_parse(HobColors.GRAY)) ctx.paint()
cr.rectangle(x + w, y, self.width - x - w, h) # last rectangle
cr.fill()
def draw_tab_text(self, cr):
style = self.get_style()
for child in self.children:
pangolayout = child["title_layout"]
if pangolayout:
fontw, fonth = pangolayout.get_pixel_size()
# center pos
off_x = (self.tab_width - fontw) / 2
off_y = (self.tab_height - fonth) / 2
x = child["x"] + off_x
y = child["y"] + off_y
if not child == self.current_child:
self.window.draw_layout(self.style.fg_gc[gtk.STATE_NORMAL], int(x), int(y), pangolayout, gtk.gdk.Color(HobColors.WHITE))
else:
self.window.draw_layout(self.style.fg_gc[gtk.STATE_NORMAL], int(x), int(y), pangolayout)
def draw_toggled_tab(self, cr):
if not self.current_child:
return
x = self.current_child["x"]
y = self.current_child["y"]
width = self.tab_width
height = self.tab_height
style = self.get_style()
color = style.base[gtk.STATE_NORMAL]
r = height / 10
if self.tab_pressed == True:
for xoff, yoff, c1, c2 in [(1, 0, HobColors.SLIGHT_DARK, HobColors.DARK), (2, 0, HobColors.GRAY, HobColors.LIGHT_GRAY)]:
cr.set_source_color(gtk.gdk.color_parse(c1))
cr.move_to(x + xoff, y + height + yoff)
cr.line_to(x + xoff, r + yoff)
cr.arc(x + r + xoff, y + r + yoff, r, math.pi, 1.5*math.pi)
cr.move_to(x + r + xoff, y + yoff)
cr.line_to(x + width - r + xoff, y + yoff)
cr.arc(x + width - r + xoff, y + r + yoff, r, 1.5*math.pi, 2*math.pi)
cr.stroke()
cr.set_source_color(gtk.gdk.color_parse(c2))
cr.move_to(x + width + xoff, r + yoff)
cr.line_to(x + width + xoff, y + height + yoff)
cr.line_to(x + xoff, y + height + yoff)
cr.stroke()
x = x + 2
y = y + 2
cr.set_source_rgba(color.red, color.green, color.blue, 1)
cr.move_to(x + r, y)
cr.line_to(x + width - r , y)
cr.arc(x + width - r, y + r, r, 1.5*math.pi, 2*math.pi)
cr.move_to(x + width, r)
cr.line_to(x + width, y + height)
cr.line_to(x, y + height)
cr.line_to(x, r)
cr.arc(x + r, y + r, r, math.pi, 1.5*math.pi)
cr.fill()
def draw_indicator(self, cr, child):
text = ("%d" % child["indicator_number"])
layout = self.create_pango_layout(text)
layout.set_font_description(self.font)
textw, texth = layout.get_pixel_size()
# draw the back round area
tab_x = child["x"]
tab_y = child["y"]
dest_w = int(32 * self.tab_w_ratio)
dest_h = int(32 * self.tab_h_ratio)
if dest_h < self.tab_height:
dest_w = dest_h
# x position is offset(tab_width*3/4 - icon_width/2) + start_pos(tab_x)
x = tab_x + self.tab_width * 3/4 - dest_w/2
y = tab_y + self.tab_height/2 - dest_h/2
r = min(dest_w, dest_h)/2
if not child == self.current_child:
color = cr.set_source_color(gtk.gdk.color_parse(HobColors.DEEP_RED))
else:
color = cr.set_source_color(gtk.gdk.color_parse(HobColors.GRAY))
# check round back area can contain the text or not
back_round_can_contain_width = float(2 * r * 0.707)
if float(textw) > back_round_can_contain_width:
xoff = (textw - int(back_round_can_contain_width)) / 2
cr.move_to(x + r - xoff, y + r + r)
cr.arc((x + r - xoff), (y + r), r, 0.5*math.pi, 1.5*math.pi)
cr.fill() # left half round
cr.rectangle((x + r - xoff), y, 2 * xoff, 2 * r)
cr.fill() # center rectangle
cr.arc((x + r + xoff), (y + r), r, 1.5*math.pi, 0.5*math.pi)
cr.fill() # right half round
else:
cr.arc((x + r), (y + r), r, 0, 2*math.pi)
cr.fill()
# draw the number text
x = x + (dest_w/2)-(textw/2)
y = y + (dest_h/2) - (texth/2)
cr.move_to(x, y)
self.window.draw_layout(self.style.fg_gc[gtk.STATE_NORMAL], int(x), int(y), layout, gtk.gdk.Color(HobColors.WHITE))
def show_indicator_icon(self, child, number):
child["indicator_show"] = True
child["indicator_number"] = number
self.queue_draw()
def hide_indicator_icon(self, child):
child["indicator_show"] = False
self.queue_draw()
def set_blank_size(self, x, y, w, h):
if not self.blank_rectangle or self.blank_rectangle.x != x or self.blank_rectangle.width != w:
self.emit("blank-area-changed", x, y, w, h)
return gtk.gdk.Rectangle(x, y, w, h)
def query_tooltip_cb(self, widget, x, y, keyboardtip, tooltip):
if keyboardtip or (not tooltip):
return False
# check which tab be clicked
for child in self.children:
if (child["x"] < x) and (x < child["x"] + self.tab_width) \
and (child["y"] < y) and (y < child["y"] + self.tab_height):
tooltip.set_markup(child["tooltip_markup"])
return True
return False return False
class HobNotebook(gtk.VBox): def set_count(self, count):
self.indicator.set_count(count)
def set_active(self, active=True):
self.indicator.set_active(active)
class HobNotebook(gtk.Notebook):
def __init__(self): def __init__(self):
gtk.VBox.__init__(self, False, 0) gtk.Notebook.__init__(self)
self.set_property('homogeneous', True)
self.notebook = gtk.Notebook() self.pages = []
self.notebook.set_property('homogeneous', True)
self.notebook.set_property('show-tabs', False)
self.tabbar = HobTabBar()
self.tabbar.connect("tab-switched", self.tab_switched_cb)
self.notebook.connect("page-added", self.page_added_cb)
self.notebook.connect("page-removed", self.page_removed_cb)
self.search = None self.search = None
self.search_name = "" self.search_name = ""
self.tb = gtk.Table(1, 100, False) self.connect("switch-page", self.page_changed_cb)
self.hbox= gtk.HBox(False, 0)
self.hbox.pack_start(self.tabbar, True, True)
self.tb.attach(self.hbox, 0, 100, 0, 1)
self.pack_start(self.tb, False, False)
self.pack_start(self.notebook)
self.show_all() self.show_all()
def append_page(self, child, tab_label): def page_changed_cb(self, nb, page, page_num):
self.notebook.set_current_page(self.notebook.append_page(child, tab_label)) for p, lbl in enumerate(self.pages):
if p == page_num:
lbl.set_active()
else:
lbl.set_active(False)
def append_page(self, child, tab_label, tab_tooltip=None):
label = HobTabLabel(tab_label)
if tab_tooltip:
label.set_tooltip_text(tab_tooltip)
label.set_active(False)
self.pages.append(label)
gtk.Notebook.append_page(self, child, label)
def set_entry(self, name="Search:"): def set_entry(self, name="Search:"):
for child in self.tb.get_children():
if child:
self.tb.remove(child)
hbox_entry = gtk.HBox(False, 0)
hbox_entry.show()
self.search = gtk.Entry() self.search = gtk.Entry()
self.search_name = name self.search_name = name
style = self.search.get_style() style = self.search.get_style()
@ -763,59 +531,20 @@ class HobNotebook(gtk.VBox):
self.search.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY, gtk.STOCK_CLEAR) self.search.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY, gtk.STOCK_CLEAR)
self.search.connect("icon-release", self.set_search_entry_clear_cb) self.search.connect("icon-release", self.set_search_entry_clear_cb)
self.search.show() self.search.show()
self.align = gtk.Alignment(xalign=1.0, yalign=0.7)
self.align.add(self.search)
self.align.show()
hbox_entry.pack_end(self.align, False, False)
self.tabbar.resize_blank_rectangle()
self.tb.attach(hbox_entry, 75, 100, 0, 1, xpadding=5)
self.tb.attach(self.hbox, 0, 100, 0, 1)
self.tabbar.connect("blank-area-changed", self.blank_area_resize_cb)
self.search.connect("focus-in-event", self.set_search_entry_editable_cb) self.search.connect("focus-in-event", self.set_search_entry_editable_cb)
self.search.connect("focus-out-event", self.set_search_entry_reset_cb) self.search.connect("focus-out-event", self.set_search_entry_reset_cb)
self.set_action_widget(self.search, gtk.PACK_END)
self.tb.show()
def show_indicator_icon(self, title, number): def show_indicator_icon(self, title, number):
for child in self.tabbar.children: for child in self.pages:
if child["toggled_page"] == -1: if child.lbl.get_label() == title:
continue child.set_count(number)
if child["title"] == title:
self.tabbar.show_indicator_icon(child, number)
def hide_indicator_icon(self, title): def hide_indicator_icon(self, title):
for child in self.tabbar.children: for child in self.pages:
if child["toggled_page"] == -1: if child.lbl.get_label() == title:
continue child.set_count(0)
if child["title"] == title:
self.tabbar.hide_indicator_icon(child)
def tab_switched_cb(self, widget, page):
self.notebook.set_current_page(page)
def page_added_cb(self, notebook, notebook_child, page):
if not notebook:
return
title = notebook.get_tab_label_text(notebook_child)
label = notebook.get_tab_label(notebook_child)
tooltip_markup = label.get_tooltip_markup()
if not title:
return
for child in self.tabbar.children:
if child["title"] == title:
child["toggled_page"] = page
return
self.tabbar.append_tab_child(title, page, tooltip_markup)
def page_removed_cb(self, notebook, notebook_child, page, title=""):
for child in self.tabbar.children:
if child["title"] == title:
child["toggled_page"] = -1
def blank_area_resize_cb(self, widget, request_x, request_y, request_width, request_height):
self.search.set_size_request(request_width, request_height)
def set_search_entry_editable_cb(self, search, event): def set_search_entry_editable_cb(self, search, event):
search.set_editable(True) search.set_editable(True)

View File

@ -129,8 +129,7 @@ class PackageSelectionPage (HobPage):
if page['name'] == "Included": if page['name'] == "Included":
tab.connect("button-release-event", self.button_click_cb) tab.connect("button-release-event", self.button_click_cb)
tab.connect("cell-fadeinout-stopped", self.after_fadeout_checkin_include) tab.connect("cell-fadeinout-stopped", self.after_fadeout_checkin_include)
label = gtk.Label(page['name']) self.ins.append_page(tab, page['name'])
self.ins.append_page(tab, label)
self.tables.append(tab) self.tables.append(tab)
self.ins.set_entry("Search packages:") self.ins.set_entry("Search packages:")

View File

@ -153,10 +153,7 @@ class RecipeSelectionPage (HobPage):
if page['name'] == "Included": if page['name'] == "Included":
tab.connect("button-release-event", self.button_click_cb) tab.connect("button-release-event", self.button_click_cb)
tab.connect("cell-fadeinout-stopped", self.after_fadeout_checkin_include) tab.connect("cell-fadeinout-stopped", self.after_fadeout_checkin_include)
label = gtk.Label(page['name']) self.ins.append_page(tab, page['name'], page['tooltip'])
label.set_selectable(False)
label.set_tooltip_text(page['tooltip'])
self.ins.append_page(tab, label)
self.tables.append(tab) self.tables.append(tab)
self.ins.set_entry("Search recipes:") self.ins.set_entry("Search recipes:")