Hob GUI tweaks v2
cover Hob GUI tweaks v2
Here are some tweaks to the Hob GUI. This series iterates on (and therefore makes redundant) an earlier series with the same subject.
Changes include
* adding a clear icon to search entries, per Gtk+ norm
* changes to PersistentTooltip's so that the colours work better on darker themes (though there's still a problem with the link colour, which is technically a theme bug but makes our app look bad), some spacing tweaks and a change to reindent the file to match the rest of BitBake indentation style.
* add a new widget, HobAltButton, for use as a secondary button instead of gtk.LinkButton - Belen, our interaction designer, informed me that the design intends them to be buttons (and therefore have prelight and active states matching standard buttons) but that they are supposed to be implemented without relief so that the user is guided towards primary actions. I need to develop a follow on that changes the colour of the secondary button text per visual design.
* Replace HobXpmLabelButtonBox with a new HobImageButton, this is a HobAltButton subclass which is modelled after the buttons in gnome-disk-utility, where Belen informs me the buttons on the main page for Layers, Recipes and Packages are modelled after.
* Finally I include a further iterated implementation of the Layer Selection dialogue which uses some new assets provided by the design team and the HobAltButton to match the visual and interation designs more closely.
Cheers,
Joshua
The following changes since commit c5fdc6c02fe4712d3114caccfd759a626bd9677b:
Add bitbake-dumpsig to make it more obvious how to dump a signatures file (2012-03-21 17:08:08 +0000)
are available in the git repository at:
git://github.com/incandescant/bitbake josh/hob
https://github.com/incandescant/bitbake/tree/josh/hob
Joshua Lock (10):
ui/crumbs/hobwidget: add clear icon to search entries in HobNotebook ui/crumbs/persistenttooltip: tweak borders ui/crumbs/persistenttooltip: fix colours on darker themes ui/crumbs/persistenttooltip: fix whitespace lib/bb/ui/crumbs: Add HobAltButton and use it lib/ui/icons: autocrop images
lib/bb/ui/crumbs: replace HobXpmLabelButtonBox with HobImageButton lib/bb/ui/crumbs: add icons for use in the layer dialogue ui/crumbs/hig: make the layer selection dialogue more closely match
design
lib/bb/ui/crumbs/hig: disable removal of meta-hob layer
lib/bb/ui/crumbs/builddetailspage.py | 6 +- lib/bb/ui/crumbs/hig.py | 129 ++++++++++---- lib/bb/ui/crumbs/hobwidget.py | 131 +++++++------- lib/bb/ui/crumbs/imageconfigurationpage.py | 52 +++--- lib/bb/ui/crumbs/imagedetailspage.py | 12 +- lib/bb/ui/crumbs/packageselectionpage.py | 4 +- lib/bb/ui/crumbs/persistenttooltip.py | 244 +++++++++++++----------- lib/bb/ui/crumbs/recipeselectionpage.py | 4 +- lib/bb/ui/icons/indicators/add.png | Bin 0 -> 1176 bytes lib/bb/ui/icons/indicators/remove.png | Bin 0 -> 1971 bytes lib/bb/ui/icons/layers/layers_display.png | Bin 5326 -> 4840 bytes lib/bb/ui/icons/packages/packages_display.png | Bin 7188 -> 7011 bytes lib/bb/ui/icons/recipe/recipe_display.png | Bin 4873 -> 4723 bytes 13 files changed, 334 insertions(+), 248 deletions(-) create mode 100644 lib/bb/ui/icons/indicators/add.png create mode 100644 lib/bb/ui/icons/indicators/remove.png
Signature · 1 line
1.7.7.6
PATCH 1/10 ui/crumbs/hobwidget: add clear icon to search entries in HobNotebook
It's a common pattern on Gtk+ desktops to be able to clear a search/filter entry using an icon in that entry.
--- lib/bb/ui/crumbs/hobwidget.py | 19 ++++++++++++++----- 1 files changed, 14 insertions(+), 5 deletions(-)
lib/bb/ui/crumbs/hobwidget.py +14 -5
@@ -622,6 +622,8 @@ class HobNotebook(gtk.VBox): self.search.set_style(style) self.search.set_text(name) self.search.set_editable(False) + 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.show() self.align = gtk.Alignment(xalign=1.0, yalign=0.7) self.align.add(self.search)
@@ -682,9 +684,16 @@ class HobNotebook(gtk.VBox): style.text[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(HobColors.BLACK, False, False) search.set_style(style) - def set_search_entry_reset_cb(self, search, event): - style = search.get_style() + def reset_entry(self, entry): + style = entry.get_style() style.text[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(HobColors.GRAY, False, False) - search.set_style(style) - search.set_text(self.search_name) - search.set_editable(False) + entry.set_style(style) + entry.set_text(self.search_name) + entry.set_editable(False) + + def set_search_entry_reset_cb(self, search, event): + self.reset_entry(search) + + def set_search_entry_clear_cb(self, search, icon_pos, event): + self.reset_entry(search) +
Signature · 1 line
1.7.7.6
PATCH 2/10 ui/crumbs/persistenttooltip: tweak borders
In reply to Joshua LockChange the layout and borders so that the close button is flush with the edge of the tooltip window yet leave the contents with a small border such that text isn't flush with the window edge.
--- lib/bb/ui/crumbs/persistenttooltip.py | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-)
lib/bb/ui/crumbs/persistenttooltip.py +6 -2
@@ -64,7 +64,7 @@ class PersistentTooltip(gtk.Window): # We must be modal to ensure we grab focus when presented from a gtk.Dialog self.set_modal(True) - self.set_border_width(6) + self.set_border_width(0) self.set_position(gtk.WIN_POS_MOUSE) self.set_opacity(0.95)
@@ -91,10 +91,14 @@ class PersistentTooltip(gtk.Window): self.set_default(self.button) + hbox = gtk.HBox(True, 6) + hbox.set_border_width(6) + hbox.show() + vbox.pack_end(hbox, True, True, 6) self.label = gtk.Label() self.label.set_markup(markup) self.label.show() - vbox.pack_end(self.label, True, True, 6) + hbox.pack_end(self.label, True, True, 6) self.connect("key-press-event", self._catch_esc_cb)
Signature · 1 line
1.7.7.6
PATCH 3/10 ui/crumbs/persistenttooltip: fix colours on darker themes
In reply to Joshua LockDarker gtk+ themes, such as the one used in Ubuntu Unity, revealed that the PersistentTooltip styling wasn't setting the label colour correctly.
Set the label foreground colour to the tooltip_fg_colour value as read from gtk-color-scheme property of the system settings.
--- lib/bb/ui/crumbs/persistenttooltip.py | 26 +++++++++++++++++++++----- 1 files changed, 21 insertions(+), 5 deletions(-)
lib/bb/ui/crumbs/persistenttooltip.py +21 -5
@@ -38,6 +38,11 @@ class PersistentTooltip(gtk.Window): def __init__(self, markup): gtk.Window.__init__(self, gtk.WINDOW_POPUP) + # Inherit the system theme for a tooltip + style = gtk.rc_get_style_by_paths(gtk.settings_get_default(), + 'gtk-tooltip', 'gtk-tooltip', gobject.TYPE_NONE) + self.set_style(style) + # The placement of the close button on the tip should reflect how the # window manager of the users system places close buttons. Try to read # the metacity gconf key to determine whether the close button is on the
@@ -96,17 +101,28 @@ class PersistentTooltip(gtk.Window): hbox.show() vbox.pack_end(hbox, True, True, 6) self.label = gtk.Label() + # We want to match the colours of the normal tooltips, as dictated by + # the users gtk+-2.0 theme, wherever possible - on some systems this + # requires explicitly setting a fg_color for the label which matches the + # tooltip_fg_color + settings = gtk.settings_get_default() + colours = settings.get_property('gtk-color-scheme').split('\n') + # remove any empty lines, there's likely to be a trailing one after + # calling split on a dictionary-like string + colours = filter(None, colours) + for col in colours: + item, val = col.split(': ') + if item == 'tooltip_fg_color': + style = self.label.get_style() + style.fg[gtk.STATE_NORMAL] = gtk.gdk.color_parse(val) + self.label.set_style(style) + break # we only care for the tooltip_fg_color self.label.set_markup(markup) self.label.show() hbox.pack_end(self.label, True, True, 6) self.connect("key-press-event", self._catch_esc_cb) - # Inherit the system theme for a tooltip - style = gtk.rc_get_style_by_paths(gtk.settings_get_default(), - 'gtk-tooltip', 'gtk-tooltip', gobject.TYPE_NONE) - self.set_style(style) - self.add(vbox) """
Signature · 1 line
1.7.7.6
PATCH 4/10 ui/crumbs/persistenttooltip: fix whitespace
In reply to Joshua LockWe use 4 spaces, not a tab, in BitBake
--- lib/bb/ui/crumbs/persistenttooltip.py | 264 ++++++++++++++++---------------- 1 files changed, 132 insertions(+), 132 deletions(-)
lib/bb/ui/crumbs/persistenttooltip.py +132 -132
@@ -26,135 +26,135 @@ except: pass class PersistentTooltip(gtk.Window): - """ - A tooltip which persists once shown until the user dismisses it with the Esc - key or by clicking the close button. - - # FIXME: the PersistentTooltip should be disabled when the user clicks anywhere off - # it. We can't do this with focus-out-event becuase modal ensures we have focus? - - markup: some Pango text markup to display in the tooltip - """ - def __init__(self, markup): - gtk.Window.__init__(self, gtk.WINDOW_POPUP) - - # Inherit the system theme for a tooltip - style = gtk.rc_get_style_by_paths(gtk.settings_get_default(), - 'gtk-tooltip', 'gtk-tooltip', gobject.TYPE_NONE) - self.set_style(style) - - # The placement of the close button on the tip should reflect how the - # window manager of the users system places close buttons. Try to read - # the metacity gconf key to determine whether the close button is on the - # left or the right. - # In the case that we can't determine the users configuration we default - # to close buttons being on the right. - __button_right = True - try: - client = gconf.client_get_default() - order = client.get_string("/apps/metacity/general/button_layout") - if order and order.endswith(":"): - __button_right = False - except NameError: - pass - - # We need to ensure we're only shown once - self.shown = False - - # We don't want any WM decorations - self.set_decorated(False) - # We don't want to show in the taskbar or window switcher - self.set_skip_pager_hint(True) - self.set_skip_taskbar_hint(True) - # We must be modal to ensure we grab focus when presented from a gtk.Dialog - self.set_modal(True) - - self.set_border_width(0) - self.set_position(gtk.WIN_POS_MOUSE) - self.set_opacity(0.95) - - # Draw our label and close buttons - hbox = gtk.HBox(False, 0) - hbox.show() - vbox = gtk.VBox(False, 0) - vbox.show() - vbox.pack_start(hbox, True, True, 0) - - img = gtk.Image() - img.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_BUTTON) - - self.button = gtk.Button() - self.button.set_image(img) - self.button.connect("clicked", self._dismiss_cb) - self.button.set_can_default(True) - self.button.grab_focus() - self.button.show() - if __button_right: - hbox.pack_end(self.button, False, False, 0) - else: - hbox.pack_start(self.button, False, False, 0) - - self.set_default(self.button) - - hbox = gtk.HBox(True, 6) - hbox.set_border_width(6) - hbox.show() - vbox.pack_end(hbox, True, True, 6) - self.label = gtk.Label() - # We want to match the colours of the normal tooltips, as dictated by - # the users gtk+-2.0 theme, wherever possible - on some systems this - # requires explicitly setting a fg_color for the label which matches the - # tooltip_fg_color - settings = gtk.settings_get_default() - colours = settings.get_property('gtk-color-scheme').split('\n') - # remove any empty lines, there's likely to be a trailing one after - # calling split on a dictionary-like string - colours = filter(None, colours) - for col in colours: - item, val = col.split(': ') - if item == 'tooltip_fg_color': - style = self.label.get_style() - style.fg[gtk.STATE_NORMAL] = gtk.gdk.color_parse(val) - self.label.set_style(style) - break # we only care for the tooltip_fg_color - self.label.set_markup(markup) - self.label.show() - hbox.pack_end(self.label, True, True, 6) - - self.connect("key-press-event", self._catch_esc_cb) - - self.add(vbox) - - """ - Callback when the PersistentTooltip's close button is clicked. - Hides the PersistentTooltip. - """ - def _dismiss_cb(self, button): - self.hide() - return True - - """ - Callback when the Esc key is detected. Hides the PersistentTooltip. - """ - def _catch_esc_cb(self, widget, event): - keyname = gtk.gdk.keyval_name(event.keyval) - if keyname == "Escape": - self.hide() - return True - - """ - Called to present the PersistentTooltip. - Overrides the superclasses show() method to include state tracking. - """ - def show(self): - if not self.shown: - self.shown = True - gtk.Window.show(self) - - """ - Called to hide the PersistentTooltip. - Overrides the superclasses hide() method to include state tracking. - """ - def hide(self): - self.shown = False - gtk.Window.hide(self) + """ + A tooltip which persists once shown until the user dismisses it with the Esc + key or by clicking the close button. + + # FIXME: the PersistentTooltip should be disabled when the user clicks anywhere off + # it. We can't do this with focus-out-event becuase modal ensures we have focus? + + markup: some Pango text markup to display in the tooltip + """ + def __init__(self, markup): + gtk.Window.__init__(self, gtk.WINDOW_POPUP) + + # Inherit the system theme for a tooltip + style = gtk.rc_get_style_by_paths(gtk.settings_get_default(), + 'gtk-tooltip', 'gtk-tooltip', gobject.TYPE_NONE) + self.set_style(style) + + # The placement of the close button on the tip should reflect how the + # window manager of the users system places close buttons. Try to read + # the metacity gconf key to determine whether the close button is on the + # left or the right. + # In the case that we can't determine the users configuration we default + # to close buttons being on the right. + __button_right = True + try: + client = gconf.client_get_default() + order = client.get_string("/apps/metacity/general/button_layout") + if order and order.endswith(":"): + __button_right = False + except NameError: + pass + + # We need to ensure we're only shown once + self.shown = False + + # We don't want any WM decorations + self.set_decorated(False) + # We don't want to show in the taskbar or window switcher + self.set_skip_pager_hint(True) + self.set_skip_taskbar_hint(True) + # We must be modal to ensure we grab focus when presented from a gtk.Dialog + self.set_modal(True) + + self.set_border_width(0) + self.set_position(gtk.WIN_POS_MOUSE) + self.set_opacity(0.95) + + # Draw our label and close buttons + hbox = gtk.HBox(False, 0) + hbox.show() + vbox = gtk.VBox(False, 0) + vbox.show() + vbox.pack_start(hbox, True, True, 0) + + img = gtk.Image() + img.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_BUTTON) + + self.button = gtk.Button() + self.button.set_image(img) + self.button.connect("clicked", self._dismiss_cb) + self.button.set_can_default(True) + self.button.grab_focus() + self.button.show() + if __button_right: + hbox.pack_end(self.button, False, False, 0) + else: + hbox.pack_start(self.button, False, False, 0) + + self.set_default(self.button) + + hbox = gtk.HBox(True, 6) + hbox.set_border_width(6) + hbox.show() + vbox.pack_end(hbox, True, True, 6) + self.label = gtk.Label() + # We want to match the colours of the normal tooltips, as dictated by + # the users gtk+-2.0 theme, wherever possible - on some systems this + # requires explicitly setting a fg_color for the label which matches the + # tooltip_fg_color + settings = gtk.settings_get_default() + colours = settings.get_property('gtk-color-scheme').split('\n') + # remove any empty lines, there's likely to be a trailing one after + # calling split on a dictionary-like string + colours = filter(None, colours) + for col in colours: + item, val = col.split(': ') + if item == 'tooltip_fg_color': + style = self.label.get_style() + style.fg[gtk.STATE_NORMAL] = gtk.gdk.color_parse(val) + self.label.set_style(style) + break # we only care for the tooltip_fg_color + self.label.set_markup(markup) + self.label.show() + hbox.pack_end(self.label, True, True, 6) + + self.connect("key-press-event", self._catch_esc_cb) + + self.add(vbox) + + """ + Callback when the PersistentTooltip's close button is clicked. + Hides the PersistentTooltip. + """ + def _dismiss_cb(self, button): + self.hide() + return True + + """ + Callback when the Esc key is detected. Hides the PersistentTooltip. + """ + def _catch_esc_cb(self, widget, event): + keyname = gtk.gdk.keyval_name(event.keyval) + if keyname == "Escape": + self.hide() + return True + + """ + Called to present the PersistentTooltip. + Overrides the superclasses show() method to include state tracking. + """ + def show(self): + if not self.shown: + self.shown = True + gtk.Window.show(self) + + """ + Called to hide the PersistentTooltip. + Overrides the superclasses hide() method to include state tracking. + """ + def hide(self): + self.shown = False + gtk.Window.hide(self)
Signature · 1 line
1.7.7.6
PATCH 5/10 lib/bb/ui/crumbs: Add HobAltButton and use it
In reply to Joshua LockThis adds a gtk.Button subclass for secondary actions which unsets the relief so that the user is aware that the button is clickable and yet it is more subtle than the primary action (such that the primary action is the most obvious one) - this is per the interaction design.
Further we replace all uses of gtk.LinkButton with the new HobAltButton
Partially addresses [YOCTO #2105], a follow on patch will theme the button so that it matches the visual design.
--- lib/bb/ui/crumbs/builddetailspage.py | 6 +++--- lib/bb/ui/crumbs/hig.py | 2 +- lib/bb/ui/crumbs/hobwidget.py | 9 ++++++++- lib/bb/ui/crumbs/imageconfigurationpage.py | 13 ++++++------- lib/bb/ui/crumbs/imagedetailspage.py | 12 ++++++------ lib/bb/ui/crumbs/packageselectionpage.py | 4 ++-- lib/bb/ui/crumbs/recipeselectionpage.py | 4 ++-- 7 files changed, 28 insertions(+), 22 deletions(-)
lib/bb/ui/crumbs/builddetailspage.py +3 -3
@@ -22,7 +22,7 @@ import gtk from bb.ui.crumbs.progressbar import HobProgressBar -from bb.ui.crumbs.hobwidget import hic, HobNotebook +from bb.ui.crumbs.hobwidget import hic, HobNotebook, HobAltButton from bb.ui.crumbs.runningbuild import RunningBuildTreeView from bb.ui.crumbs.runningbuild import BuildConfigurationTreeView from bb.ui.crumbs.runningbuild import BuildFailureTreeView
@@ -49,7 +49,7 @@ class BuildDetailsPage (HobPage): self.progress_box = gtk.HBox(False, 6) self.progress_bar = HobProgressBar() self.progress_box.pack_start(self.progress_bar, expand=True, fill=True) - self.stop_button = gtk.LinkButton("Stop the build process", "Stop") + self.stop_button = HobAltButton("Stop") self.stop_button.connect("clicked", self.stop_button_clicked_cb) self.progress_box.pack_end(self.stop_button, expand=False, fill=False)
@@ -78,7 +78,7 @@ class BuildDetailsPage (HobPage): self.notebook.append_page(self.scrolled_view_build, gtk.Label("Log")) self.button_box = gtk.HBox(False, 6) - self.back_button = gtk.LinkButton("Go back to Image Configuration screen", "<< Back to image configuration") + self.back_button = HobAltButton("Back to image configuration") self.back_button.connect("clicked", self.back_button_clicked_cb) self.button_box.pack_start(self.back_button, expand=False, fill=False)
lib/bb/ui/crumbs/hig.py +1 -1
@@ -28,7 +28,7 @@ import re import subprocess import shlex from bb.ui.crumbs.hobcolor import HobColors -from bb.ui.crumbs.hobwidget import hcc, hic, HobViewTable, HobInfoButton +from bb.ui.crumbs.hobwidget import hcc, hic, HobViewTable, HobInfoButton, HobAltButton from bb.ui.crumbs.progressbar import HobProgressBar """
lib/bb/ui/crumbs/hobwidget.py +8 -1
@@ -171,11 +171,18 @@ class HobViewTable (gtk.VBox): if not view_column.get_title() in self.toggle_columns: self.emit("row-activated", tree.get_model(), path) +class HobAltButton(gtk.Button): + """ + A gtk.Button subclass which has no relief, and so is more discrete + """ + def __init__(self, label=None): + gtk.Button.__init__(self, label) + self.set_relief(gtk.RELIEF_NONE) + class HobXpmLabelButtonBox(gtk.EventBox): """ label: name of buttonbox description: the simple description """ - def __init__(self, display_file="", hover_file="", label="", description=""): gtk.EventBox.__init__(self) self._base_state_flags = gtk.STATE_NORMAL
lib/bb/ui/crumbs/imageconfigurationpage.py +6 -7
@@ -24,7 +24,7 @@ import gtk import glib from bb.ui.crumbs.progressbar import HobProgressBar from bb.ui.crumbs.hobcolor import HobColors -from bb.ui.crumbs.hobwidget import hic, HobXpmLabelButtonBox, HobInfoButton +from bb.ui.crumbs.hobwidget import hic, HobXpmLabelButtonBox, HobInfoButton, HobAltButton from bb.ui.crumbs.hoblistmodel import RecipeListModel from bb.ui.crumbs.hobpages import HobPage
@@ -153,7 +153,7 @@ class ImageConfigurationPage (HobPage): self.progress_box = gtk.HBox(False, 6) self.progress_bar = HobProgressBar() self.progress_box.pack_start(self.progress_bar, expand=True, fill=True) - self.stop_button = gtk.LinkButton("Stop the parsing process", "Stop") + self.stop_button = HobAltButton("Stop") self.stop_button.connect("clicked", self.stop_button_clicked_cb) self.progress_box.pack_end(self.stop_button, expand=False, fill=False)
@@ -241,8 +241,7 @@ class ImageConfigurationPage (HobPage): button_box.pack_end(label, expand=False, fill=False) # create button "Build Packages" - build_packages_button = gtk.LinkButton("Build packages first based on recipe selection " - "for late customization on packages for the target image", "Build Packages") + build_packages_button = HobAltButton("Build Packages") build_packages_button.connect("clicked", self.build_packages_button_clicked_cb) button_box.pack_end(build_packages_button, expand=False, fill=False)
@@ -341,14 +340,14 @@ class ImageConfigurationPage (HobPage): self.image_combo.set_active(-1) self.image_combo.set_active(active) - def layer_button_clicked_cb(self, event, data): + def layer_button_clicked_cb(self, button): # Create a layer selection dialog self.builder.show_layer_selection_dialog() - def view_recipes_button_clicked_cb(self, event, data): + def view_recipes_button_clicked_cb(self, button): self.builder.show_recipes() - def view_packages_button_clicked_cb(self, event, data): + def view_packages_button_clicked_cb(self, button): self.builder.show_packages() def just_bake_button_clicked_cb(self, button):
lib/bb/ui/crumbs/imagedetailspage.py +6 -6
@@ -23,7 +23,7 @@ import gobject import gtk from bb.ui.crumbs.hobcolor import HobColors -from bb.ui.crumbs.hobwidget import hic, HobViewTable +from bb.ui.crumbs.hobwidget import hic, HobViewTable, HobAltButton from bb.ui.crumbs.hobpages import HobPage #
@@ -213,7 +213,7 @@ class ImageDetailsPage (HobPage): vallist.append(layer) i += 1 - edit_config_button = gtk.LinkButton("Changes settings for build", "Edit configuration") + edit_config_button = HobAltButton("Edit configuration") edit_config_button.connect("clicked", self.edit_config_button_clicked_cb) setting_detail = self.DetailBox(varlist=varlist, vallist=vallist, button=edit_config_button) self.box_group_area.pack_start(setting_detail, expand=False, fill=False)
@@ -224,7 +224,7 @@ class ImageDetailsPage (HobPage): vallist.append(pkg_num) vallist.append(image_size) if build_succeeded: - edit_packages_button = gtk.LinkButton("Change package selection for customization", "Edit packages") + edit_packages_button = HobAltButton("Edit packages") edit_packages_button.connect("clicked", self.edit_packages_button_clicked_cb) else: # get to this page from "My images" edit_packages_button = None
@@ -288,7 +288,7 @@ class ImageDetailsPage (HobPage): bottom_buttons.pack_end(label, expand=False, fill=False) # create button "Run image" - run_button = gtk.LinkButton("Launch and boot the image in the QEMU emulator", "Run image") + run_button = HobAltButton("Run image") run_button.connect("clicked", self.run_button_clicked_cb) bottom_buttons.pack_end(run_button, expand=False, fill=False) created = True
@@ -301,7 +301,7 @@ class ImageDetailsPage (HobPage): bottom_buttons.pack_end(label, expand=False, fill=False) # create button "Save as template" - save_button = gtk.LinkButton("Save the hob build template for future use", "Save as template") + save_button = HobAltButton("Save as template") save_button.connect("clicked", self.save_button_clicked_cb) bottom_buttons.pack_end(save_button, expand=False, fill=False) create = True
@@ -309,7 +309,7 @@ class ImageDetailsPage (HobPage): name = "Build new image" if name in buttonlist: # create button "Build new image" - build_new_button = gtk.LinkButton("Initiate another new build from the beginning", "Build new image") + build_new_button = HobAltButton("Build new image") build_new_button.connect("clicked", self.build_new_button_clicked_cb) bottom_buttons.pack_start(build_new_button, expand=False, fill=False)
lib/bb/ui/crumbs/packageselectionpage.py +2 -2
@@ -23,7 +23,7 @@ import gtk import glib from bb.ui.crumbs.hobcolor import HobColors -from bb.ui.crumbs.hobwidget import HobViewTable, HobNotebook +from bb.ui.crumbs.hobwidget import HobViewTable, HobNotebook, HobAltButton from bb.ui.crumbs.hoblistmodel import PackageListModel from bb.ui.crumbs.hobpages import HobPage
@@ -144,7 +144,7 @@ class PackageSelectionPage (HobPage): self.build_image_button.connect("clicked", self.build_image_clicked_cb) button_box.pack_end(self.build_image_button, expand=False, fill=False) - self.back_button = gtk.LinkButton("Go back to Image Configuration screen", "<< Back to image configuration") + self.back_button = HobAltButton("Back to image configuration") self.back_button.connect("clicked", self.back_button_clicked_cb) button_box.pack_start(self.back_button, expand=False, fill=False)
lib/bb/ui/crumbs/recipeselectionpage.py +2 -2
@@ -23,7 +23,7 @@ import gtk import glib from bb.ui.crumbs.hobcolor import HobColors -from bb.ui.crumbs.hobwidget import HobViewTable, HobNotebook +from bb.ui.crumbs.hobwidget import HobViewTable, HobNotebook, HobAltButton from bb.ui.crumbs.hoblistmodel import RecipeListModel from bb.ui.crumbs.hobpages import HobPage
@@ -166,7 +166,7 @@ class RecipeSelectionPage (HobPage): self.build_packages_button.connect("clicked", self.build_packages_clicked_cb) button_box.pack_end(self.build_packages_button, expand=False, fill=False) - self.back_button = gtk.LinkButton("Go back to Image Configuration screen", "<< Back to image configuration") + self.back_button = HobAltButton("Back to image configuration") self.back_button.connect("clicked", self.back_button_clicked_cb) button_box.pack_start(self.back_button, expand=False, fill=False)
Signature · 1 line
1.7.7.6
PATCH 6/10 lib/ui/icons: autocrop images
In reply to Joshua LockRemove transparent border from the edge of the layers_display, packages_display and recipe_display images.
--- lib/bb/ui/icons/layers/layers_display.png | Bin 5326 -> 4840 bytes lib/bb/ui/icons/packages/packages_display.png | Bin 7188 -> 7011 bytes lib/bb/ui/icons/recipe/recipe_display.png | Bin 4873 -> 4723 bytes 3 files changed, 0 insertions(+), 0 deletions(-)
lib/bb/ui/icons/layers/layers_display.png binary +0 -0
lib/bb/ui/icons/packages/packages_display.png binary +0 -0
lib/bb/ui/icons/recipe/recipe_display.png binary +0 -0
Signature · 1 line
1.7.7.6
PATCH 7/10 lib/bb/ui/crumbs: replace HobXpmLabelButtonBox with HobImageButton
In reply to Joshua LockHobImageButton is an HobAltButton subclass, and therefore behaves like a button.
Further the HobImageButton uses a new module method soften_color() to make the secondary text of the button a ligher colour, per the design.
--- lib/bb/ui/crumbs/hobwidget.py | 103 ++++++++++++--------------- lib/bb/ui/crumbs/imageconfigurationpage.py | 41 +++++------ 2 files changed, 65 insertions(+), 79 deletions(-)
lib/bb/ui/crumbs/hobwidget.py +46 -57
@@ -171,6 +171,27 @@ class HobViewTable (gtk.VBox): if not view_column.get_title() in self.toggle_columns: self.emit("row-activated", tree.get_model(), path) +""" +A method to calculate a softened value for the colour of widget when in the +provided state. + +widget: the widget whose style to use +state: the state of the widget to use the style for + +Returns a string value representing the softened colour +""" +def soften_color(widget, state=gtk.STATE_NORMAL): + # this colour munging routine is heavily inspired bu gdu_util_get_mix_color() + # from gnome-disk-utility: + # http://git.gnome.org/browse/gnome-disk-utility/tree/src/gdu-gtk/gdu-gtk.c?h=gnome-3-0 + blend = 0.5 + style = widget.get_style() + color = style.text[state] + color.red = color.red * blend + style.base[state].red * (1.0 - blend) + color.green = color.green * blend + style.base[state].green * (1.0 - blend) + color.blue = color.blue * blend + style.base[state].blue * (1.0 - blend) + return color.to_string() + class HobAltButton(gtk.Button): """ A gtk.Button subclass which has no relief, and so is more discrete
@@ -179,64 +200,32 @@ class HobAltButton(gtk.Button): gtk.Button.__init__(self, label) self.set_relief(gtk.RELIEF_NONE) -class HobXpmLabelButtonBox(gtk.EventBox): - """ label: name of buttonbox - description: the simple description +class HobImageButton(HobAltButton): """ - def __init__(self, display_file="", hover_file="", label="", description=""): - gtk.EventBox.__init__(self) - self._base_state_flags = gtk.STATE_NORMAL - self.set_events(gtk.gdk.MOTION_NOTIFY | gtk.gdk.BUTTON_PRESS | gtk.gdk.EXPOSE) - - self.connect("expose-event", self.cb) - self.connect("enter-notify-event", self.pointer_enter_cb) - self.connect("leave-notify-event", self.pointer_leave_cb) - - self.icon_hover = gtk.Image() - self.icon_hover.set_name("icon_image") - if type(hover_file) == str: - pixbuf = gtk.gdk.pixbuf_new_from_file(hover_file) - self.icon_hover.set_from_pixbuf(pixbuf) - - self.icon_display = gtk.Image() - self.icon_display.set_name("icon_image") - if type(display_file) == str: - pixbuf = gtk.gdk.pixbuf_new_from_file(display_file) - self.icon_display.set_from_pixbuf(pixbuf) - - self.tb = gtk.Table(2, 10, True) - self.tb.set_row_spacing(1, False) - self.tb.set_col_spacing(1, False) - self.add(self.tb) - self.tb.attach(self.icon_display, 0, 2, 0, 2, 0, 0) - self.tb.attach(self.icon_hover, 0, 2, 0, 2, 0, 0) - - lbl = gtk.Label() - lbl.set_alignment(0.0, 0.5) - lbl.set_markup("<span foreground=\'#1C1C1C\' font_desc=\'18px\'>%s</span>" % label) - self.tb.attach(lbl, 2, 10, 0, 1) - - lbl = gtk.Label() - lbl.set_alignment(0.0, 0.5) - lbl.set_markup("<span foreground=\'#1C1C1C\' font_desc=\'14px\'>%s</span>" % description) - self.tb.attach(lbl, 2, 10, 1, 2) - - def pointer_enter_cb(self, *args): - #if not self.is_focus(): - self.set_state(gtk.STATE_PRELIGHT) - self._base_state_flags = gtk.STATE_PRELIGHT - self.icon_hover.show() - self.icon_display.hide() - - def pointer_leave_cb(self, *args): - self.set_state(gtk.STATE_NORMAL) - self._base_state_flags = gtk.STATE_NORMAL - self.icon_display.show() - self.icon_hover.hide() - - def cb(self, w,e): - """ Hide items - first time """ - pass + A HobAltButton with an icon and two rows of text, the second of which is + displayed in a blended colour. + + primary_text: the main button label + secondary_text: optional second line of text + icon_path: path to the icon file to display on the button + """ + def __init__(self, primary_text, secondary_text="", icon_path=""): + HobAltButton.__init__(self) + hbox = gtk.HBox(False, 3) + hbox.show() + self.add(hbox) + ic = gtk.Image() + ic.set_from_file(icon_path) + ic.set_alignment(0.5, 0.0) + ic.show() + hbox.pack_start(ic, False, False, 0) + label = gtk.Label() + label.set_alignment(0.0, 0.5) + colour = soften_color(label) + mark = "%s\n<span fgcolor='%s'><small>%s</small></span>" % (primary_text, colour, secondary_text) + label.set_markup(mark) + label.show() + hbox.pack_start(label, True, True, 0) class HobInfoButton(gtk.EventBox): """
lib/bb/ui/crumbs/imageconfigurationpage.py +19 -22
76 lines not on this page · raw message
Signature · 1 line
1.7.7.6
PATCH 8/10 lib/bb/ui/crumbs: add icons for use in the layer dialogue
In reply to Joshua Lock--- lib/bb/ui/crumbs/hobwidget.py | 2 ++ lib/bb/ui/icons/indicators/add.png | Bin 0 -> 1176 bytes lib/bb/ui/icons/indicators/remove.png | Bin 0 -> 1971 bytes 3 files changed, 2 insertions(+), 0 deletions(-) create mode 100644 lib/bb/ui/icons/indicators/add.png create mode 100644 lib/bb/ui/icons/indicators/remove.png
lib/bb/ui/crumbs/hobwidget.py +2 -0
@@ -53,6 +53,8 @@ class hic: ICON_INFO_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('info/info_hover.png')) ICON_INDI_CONFIRM_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/confirmation.png')) ICON_INDI_ERROR_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/error.png')) + ICON_INDI_REMOVE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/remove.png')) + ICON_INDI_ADD = os.path.join(HOB_ICON_BASE_DIR, ('indicators/add.png')) class hcc:
lib/bb/ui/icons/indicators/add.png new file binary +0 -0
lib/bb/ui/icons/indicators/remove.png new file binary +0 -0
Signature · 1 line
1.7.7.6
PATCH 9/10 ui/crumbs/hig: make the layer selection dialogue more closely match design
In reply to Joshua LockThe layer dialogue design includes in-line remove/delete widgets next to the layer path in the tree view for all layers other than the meta layer as well as an in-line notice that the meta layer cannot be removed.
This is achieved in this patch through the use of custom cell_data_func's for the treeview to render the meta layer differently and a custom CellRenderer implementation, CellRendererPixbufActivatable, which renders a pixbuf and emits a clicked signal when the user clicks on it.
Fixes [YOCTO #2083]
--- lib/bb/ui/crumbs/hig.py | 125 +++++++++++++++++++++++++++++++++++------------ 1 files changed, 93 insertions(+), 32 deletions(-)
lib/bb/ui/crumbs/hig.py +93 -32
@@ -791,6 +791,27 @@ class DeployImageDialog (CrumbsDialog): os.close(f_from) os.close(f_to) self.progress_bar.hide() + +class CellRendererPixbufActivatable(gtk.CellRendererPixbuf): + """ + A custom CellRenderer implementation which is activatable + so that we can handle user clicks + """ + __gsignals__ = { 'clicked' : (gobject.SIGNAL_RUN_LAST, + gobject.TYPE_NONE, + (gobject.TYPE_STRING,)), } + + def __init__(self): + gtk.CellRendererPixbuf.__init__(self) + self.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE) + self.set_property('follow-state', True) + + """ + Respond to a user click on a cell + """ + def do_activate(self, even, widget, path, background_area, cell_area, flags): + self.emit('clicked', path) + # # LayerSelectionDialog #
@@ -857,13 +878,13 @@ class LayerSelectionDialog (CrumbsDialog): layer_tv.set_rules_hint(True) layer_tv.set_headers_visible(False) tree_selection = layer_tv.get_selection() - tree_selection.set_mode(gtk.SELECTION_SINGLE) + tree_selection.set_mode(gtk.SELECTION_NONE) col0= gtk.TreeViewColumn('Path') cell0 = gtk.CellRendererText() cell0.set_padding(5,2) col0.pack_start(cell0, True) - col0.set_attributes(cell0, text=0) + col0.set_cell_data_func(cell0, self.draw_layer_path_cb) layer_tv.append_column(col0) scroll = gtk.ScrolledWindow()
@@ -899,18 +920,33 @@ class LayerSelectionDialog (CrumbsDialog): for layer in layers: layer_store.set(layer_store.append(), 0, layer) - image = gtk.Image() - image.set_from_stock(gtk.STOCK_ADD,gtk.ICON_SIZE_MENU) - add_button = gtk.Button() - add_button.set_image(image) + col1 = gtk.TreeViewColumn('Enabled') + layer_tv.append_column(col1) + + cell1 = CellRendererPixbufActivatable() + cell1.set_fixed_size(-1,35) + cell1.connect("clicked", self.del_cell_clicked_cb, layer_store) + col1.pack_start(cell1, True) + col1.set_cell_data_func(cell1, self.draw_delete_button_cb, layer_tv) + + add_button = HobAltButton() + box = gtk.HBox(False, 6) + box.show() + add_button.add(box) + im = gtk.Image() + im.set_from_file(hic.ICON_INDI_ADD) + im.show() + box.pack_start(im, expand=False, fill=False, padding=6) + lbl = gtk.Label("Add layer") + lbl.set_alignment(0.0, 0.5) + lbl.show() + box.pack_start(lbl, expand=True, fill=True, padding=6) add_button.connect("clicked", self.layer_widget_add_clicked_cb, layer_store, window) - table_layer.attach(add_button, 0, 5, 1, 2, gtk.EXPAND | gtk.FILL, 0, 0, 6) - image = gtk.Image() - image.set_from_stock(gtk.STOCK_REMOVE,gtk.ICON_SIZE_MENU) - del_button = gtk.Button() - del_button.set_image(image) - del_button.connect("clicked", self.layer_widget_del_clicked_cb, tree_selection, layer_store) - table_layer.attach(del_button, 5, 10, 1, 2, gtk.EXPAND | gtk.FILL, 0, 0, 6) + add_button.set_can_default(True) + add_button.grab_default() + add_button.set_can_focus(True) + add_button.grab_focus() + table_layer.attach(add_button, 0, 10, 1, 2, gtk.EXPAND | gtk.FILL, 0, 0, 6) layer_tv.set_model(layer_store) hbox.show_all()
@@ -927,6 +963,11 @@ class LayerSelectionDialog (CrumbsDialog): self.split_model = split_model self.layers_changed = False + # icon for remove button in TreeView + im = gtk.Image() + im.set_from_file(hic.ICON_INDI_REMOVE) + self.rem_icon = im.get_pixbuf() + # class members for internal use self.layer_store = None
@@ -935,27 +976,9 @@ class LayerSelectionDialog (CrumbsDialog): self.connect("response", self.response_cb) def create_visual_elements(self): - hbox_top = gtk.HBox() - self.vbox.pack_start(hbox_top, expand=False, fill=False) - - if self.split_model: - label = self.gen_label_widget("<b>Select Layers:</b>\n(Available layers under '${COREBASE}/layers/' directory)") - else: - label = self.gen_label_widget("<b>Select Layers:</b>") - hbox_top.pack_start(label, expand=False, fill=False) - - tooltip = "Layer is a collection of bb files and conf files" - info = HobInfoButton(tooltip, self) - hbox_top.pack_end(info, expand=False, fill=False) - layer_widget, self.layer_store = self.gen_layer_widget(self.split_model, self.layers, self.all_layers, self, None) - layer_widget.set_size_request(-1, 180) + layer_widget.set_size_request(450, 250) self.vbox.pack_start(layer_widget, expand=True, fill=True) - - label = self.gen_label_widget("<b>Note:</b> '<i>meta</i>' is the Core layer for Yocto images please do not remove it.") - label.show() - self.vbox.pack_end(label, expand=False, fill=False) - self.show_all() def response_cb(self, dialog, response_id):
@@ -974,6 +997,44 @@ class LayerSelectionDialog (CrumbsDialog): self.layers_changed = (self.layers != layers) self.layers = layers + """ + A custom cell_data_func to draw a delete 'button' in the TreeView for layers + other than the meta layer. The deletion of which is prevented so that the + user can't shoot themselves in the foot too badly. + """ + def draw_delete_button_cb(self, col, cell, model, it, tv): + path = model.get_value(it, 0) + # Trailing slashes are uncommon in bblayers.conf but confuse os.path.basename + path.rstrip('/') + name = os.path.basename(path) + if name == "meta": + cell.set_sensitive(False) + cell.set_property('pixbuf', None) + cell.set_property('mode', gtk.CELL_RENDERER_MODE_INERT) + else: + cell.set_property('pixbuf', self.rem_icon) + cell.set_sensitive(True) + cell.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE) + + return True + + """ + A custom cell_data_func to write an extra message into the layer path cell + for the meta layer. We should inform the user that they can't remove it for + their own safety. + """ + def draw_layer_path_cb(self, col, cell, model, it): + path = model.get_value(it, 0) + name = os.path.basename(path) + if name == "meta": + cell.set_property('markup', "<b>Core layer for images: it cannot be removed</b>\n%s" % path) + else: + cell.set_property('text', path) + + def del_cell_clicked_cb(self, cell, path, model): + it = model.get_iter_from_string(path) + model.remove(it) + class ImageSelectionDialog (CrumbsDialog): __columns__ = [{
Signature · 1 line
1.7.7.6
PATCH 10/10 lib/bb/ui/crumbs/hig: disable removal of meta-hob layer
In reply to Joshua LockThe Hob GUI requires the meta-hob layer to function so prevent its removal as we do with the core meta layer.
--- lib/bb/ui/crumbs/hig.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
lib/bb/ui/crumbs/hig.py +3 -1
@@ -1007,7 +1007,7 @@ class LayerSelectionDialog (CrumbsDialog): # Trailing slashes are uncommon in bblayers.conf but confuse os.path.basename path.rstrip('/') name = os.path.basename(path) - if name == "meta": + if name == "meta" or name == "meta-hob": cell.set_sensitive(False) cell.set_property('pixbuf', None) cell.set_property('mode', gtk.CELL_RENDERER_MODE_INERT)
@@ -1028,6 +1028,8 @@ class LayerSelectionDialog (CrumbsDialog): name = os.path.basename(path) if name == "meta": cell.set_property('markup', "<b>Core layer for images: it cannot be removed</b>\n%s" % path) + elif name == "meta-hob": + cell.set_property('markup', "<b>Core layer for Hob: it cannot be removed</b>\n%s" % path) else: cell.set_property('text', path)
Signature · 1 line
1.7.7.6
Quoted 6 lines · Joshua Lock
Here are some tweaks to the Hob GUI. This series iterates on (and therefore makes redundant) an earlier series with the same subject.
are available in the git repository at:
git://github.com/incandescant/bitbakejosh/hob
https://github.com/incandescant/bitbake/tree/josh/hob
Per usual I've also pushed the changes to a poky-contrib branch:
http://git.yoctoproject.org/cgit/cgit.cgi/poky-contrib/log/?h=josh/hob
Cheers,
Joshua
Signature · 3 lines
Joshua '贾詡' Lock
Yocto Project "Johannes factotum"
Intel Open Source Technology Centre05, I think we need more work, the label on the button is blue. I hope we can make the labels colorful to highlight there is a button for click. Again, for "Back to XXX", the design is "<< Back to XXX". But I can ACK to check in the patch first, and leave the work for future.
07, the machine combo box vertically is not in the middle of "layers" button, and it removes the hover function, that is when the mouse is over the button, the icon will be changed. Initially we implemented that in this way, however it didn't look good. So, we used our specific solution. What the designer expects is it becomes a button. That could be implemented.
For the rest, ACK.
Thanks.
--
Shane
Joshua Lock wrote on 2012-03-22:
Quoted 65 lines
Here are some tweaks to the Hob GUI. This series iterates on (and therefore makes redundant) an earlier series with the same subject.
Changes include
* adding a clear icon to search entries, per Gtk+ norm * changes to PersistentTooltip's so that the colours work better on darker themes (though there's still a problem with the link colour, which is technically a theme bug but makes our app look bad), some spacing tweaks and a change to reindent the file to match the rest of BitBake indentation style. * add a new widget, HobAltButton, for use as a secondary button instead of gtk.LinkButton - Belen, our interaction designer, informed me that the design intends them to be buttons (and therefore have prelight and active states matching standard buttons) but that they are supposed to be implemented without relief so that the user is guided towards primary actions. I need to develop a follow on that changes the colour of the secondary button text per visual design. * Replace HobXpmLabelButtonBox with a new HobImageButton, this is a HobAltButton subclass which is modelled after the buttons in gnome-disk-utility, where Belen informs me the buttons on the main page for Layers, Recipes and Packages are modelled after. * Finally I include a further iterated implementation of the Layer Selection dialogue which uses some new assets provided by the design team and the HobAltButton to match the visual and interation designs more closely.
Cheers,
JoshuaThe following changes since commit
c5fdc6c02fe4712d3114caccfd759a626bd9677b:Add bitbake-dumpsig to make it more obvious how to dump a signatures
file (2012-03-21 17:08:08 +0000)are available in the git repository at:
git://github.com/incandescant/bitbakejosh/hob
https://github.com/incandescant/bitbake/tree/josh/hob
Joshua Lock (10):
ui/crumbs/hobwidget: add clear icon to search entries in HobNotebook ui/crumbs/persistenttooltip: tweak borders ui/crumbs/persistenttooltip: fix colours on darker themes ui/crumbs/persistenttooltip: fix whitespacelib/bb/ui/crumbs: Add HobAltButton and use itlib/ui/icons: autocrop images
lib/bb/ui/crumbs: replace HobXpmLabelButtonBox with HobImageButtonlib/bb/ui/crumbs: add icons for use in the layer dialogue ui/crumbs/hig: make the layer selection dialogue more closely match
design
lib/bb/ui/crumbs/hig: disable removal of meta-hob layerlib/bb/ui/crumbs/builddetailspage.py | 6 +- lib/bb/ui/crumbs/hig.py | 129 ++++++++++---- lib/bb/ui/crumbs/hobwidget.py | 131 +++++++------- lib/bb/ui/crumbs/imageconfigurationpage.py | 52 +++--- lib/bb/ui/crumbs/imagedetailspage.py | 12 +- lib/bb/ui/crumbs/packageselectionpage.py | 4 +- lib/bb/ui/crumbs/persistenttooltip.py | 244 +++++++++++++----------- lib/bb/ui/crumbs/recipeselectionpage.py | 4 +- lib/bb/ui/icons/indicators/add.png | Bin 0 -> 1176 bytes lib/bb/ui/icons/indicators/remove.png | Bin 0 -> 1971 bytes lib/bb/ui/icons/layers/layers_display.png | Bin 5326 -> 4840 bytes lib/bb/ui/icons/packages/packages_display.png | Bin 7188 -> 7011 bytes lib/bb/ui/icons/recipe/recipe_display.png | Bin 4873 ->4723 bytes 13 files changed, 334 insertions(+), 248 deletions(-) create mode 100644
lib/bb/ui/icons/indicators/add.pngcreate mode 100644lib/bb/ui/icons/indicators/remove.png
Quoted 1 line · Shane
05, I think we need more work, the label on the button is blue. I hope we can make the labels colorful to highlight there is a button for click. Again, for "Back to XXX", the design is "<< Back to XXX". But I can ACK to check in the patch first, and leave the work for future.
Agreed, I mentioned the need to create a follow-on patch for the colour in the pull message. I'll work on that today. I see the design also includes the << on Back buttons, I'll include a patch to re-add those in today's series - apologies for missing that.
Quoted 1 line
07, the machine combo box vertically is not in the middle of "layers" button, and it removes the hover function, that is when the mouse is over the button, the icon will be changed. Initially we implemented that in this way, however it didn't look good. So, we used our specific solution. What the designer expects is it becomes a button. That could be implemented.
Right you are, I'd missed that on the design also. I'll fix this and ensure the use of the hover state in a follow on patch.
Cheers,
Joshua
Signature · 3 lines
Joshua '贾詡' Lock
Yocto Project "Johannes factotum"
Intel Open Source Technology Centre