From 656f9a07588cc00704825a78de9649ca4a1552b8 Mon Sep 17 00:00:00 2001 From: Dongxiao Xu Date: Mon, 28 Nov 2011 14:32:40 +0800 Subject: Hob: A new implemetation (v2) This commit implements a new design for hob Some of the new features: - Friendly new designed GUI. Quick response to user actions. - Two step builds support package generation and image generation. - Support running GUI seprarately from bitbake server. - Recipe/package selection and deselection. - Accurate customization for image contents and size. - Progress bars showing the parsing and build status. - Load/save user configurations from/into templates. (Bitbake rev: 4dacd29f9c957d20f4583330b51e5420f9c3338d) Signed-off-by: Dongxiao Xu Signed-off-by: Shane Wang Signed-off-by: Liming An Signed-off-by: Fengxia Hua Designed-by: Belen Barros Pena Signed-off-by: Richard Purdie --- bitbake/lib/bb/ui/crumbs/hobwidget.py | 805 ++++++++++++++++++++++++++++++++++ 1 file changed, 805 insertions(+) create mode 100644 bitbake/lib/bb/ui/crumbs/hobwidget.py (limited to 'bitbake/lib/bb/ui/crumbs/hobwidget.py') diff --git a/bitbake/lib/bb/ui/crumbs/hobwidget.py b/bitbake/lib/bb/ui/crumbs/hobwidget.py new file mode 100644 index 0000000000..890151ddd4 --- /dev/null +++ b/bitbake/lib/bb/ui/crumbs/hobwidget.py @@ -0,0 +1,805 @@ +# BitBake Graphical GTK User Interface +# +# Copyright (C) 2011-2012 Intel Corporation +# +# Authored by Dongxiao Xu +# Authored by Shane Wang +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import gtk +import gobject +import os +import os.path +from bb.ui.crumbs.hobcolor import HobColors + +class hwc: + + MAIN_WIN_WIDTH = 1024 + MAIN_WIN_HEIGHT = 700 + +class hic: + + HOB_ICON_BASE_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), ("ui/icons/")) + + ICON_RCIPE_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('recipe/recipe_display.png')) + ICON_RCIPE_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('recipe/recipe_hover.png')) + ICON_PACKAGES_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('packages/packages_display.png')) + ICON_PACKAGES_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('packages/packages_hover.png')) + ICON_LAYERS_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('layers/layers_display.png')) + ICON_LAYERS_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('layers/layers_hover.png')) + ICON_TEMPLATES_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('templates/templates_display.png')) + ICON_TEMPLATES_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('templates/templates_hover.png')) + ICON_IMAGES_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('images/images_display.png')) + ICON_IMAGES_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('images/images_hover.png')) + ICON_SETTINGS_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('settings/settings_display.png')) + ICON_SETTINGS_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('settings/settings_hover.png')) + ICON_INFO_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('info/info_display.png')) + 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')) + +class HobWidget: + @classmethod + def resize_widget(cls, screen, widget, widget_width, widget_height): + screen_width, screen_height = screen.get_size_request() + ratio_height = screen_width * hwc.MAIN_WIN_HEIGHT/hwc.MAIN_WIN_WIDTH + if ratio_height < screen_height: + screen_height = ratio_height + widget_width = widget_width * screen_width/hwc.MAIN_WIN_WIDTH + widget_height = widget_height * screen_height/hwc.MAIN_WIN_HEIGHT + widget.set_size_request(widget_width, widget_height) + + @classmethod + def _toggle_cb(cls, cell, path, model, column): + it = model.get_iter(path) + val = model.get_value(it, column) + val = not val + model.set(it, column, val) + + @classmethod + def _pkgfmt_up_clicked_cb(cls, button, tree_selection): + (model, it) = tree_selection.get_selected() + if not it: + return + path = model.get_path(it) + if path[0] <= 0: + return + + pre_it = model.get_iter_first() + if not pre_it: + return + else: + while model.iter_next(pre_it) : + if model.get_value(model.iter_next(pre_it), 1) != model.get_value(it, 1): + pre_it = model.iter_next(pre_it) + else: + break + + cur_index = model.get_value(it, 0) + pre_index = cur_index + if pre_it: + model.set(pre_it, 0, pre_index) + cur_index = cur_index - 1 + model.set(it, 0, cur_index) + + @classmethod + def _pkgfmt_down_clicked_cb(cls, button, tree_selection): + (model, it) = tree_selection.get_selected() + if not it: + return + next_it = model.iter_next(it) + if not next_it: + return + cur_index = model.get_value(it, 0) + next_index = cur_index + model.set(next_it, 0, next_index) + cur_index = cur_index + 1 + model.set(it, 0, cur_index) + + @classmethod + def _tree_selection_changed_cb(cls, tree_selection, button1, button2): + (model, it) = tree_selection.get_selected() + inc = model.get_value(it, 2) + if inc: + button1.set_sensitive(True) + button2.set_sensitive(True) + else: + button1.set_sensitive(False) + button2.set_sensitive(False) + + @classmethod + def _sort_func(cls, model, iter1, iter2, data): + val1 = model.get_value(iter1, 0) + val2 = model.get_value(iter2, 0) + inc1 = model.get_value(iter1, 2) + inc2 = model.get_value(iter2, 2) + if inc1 != inc2: + return inc2 - inc1 + else: + return val1 - val2 + + @classmethod + def gen_pkgfmt_widget(cls, curr_package_format, all_package_format, tooltip=""): + pkgfmt_hbox = gtk.HBox(False, 15) + + pkgfmt_store = gtk.ListStore(int, str, gobject.TYPE_BOOLEAN) + for format in curr_package_format.split(): + pkgfmt_store.set(pkgfmt_store.append(), 1, format, 2, True) + for format in all_package_format: + if format not in curr_package_format: + pkgfmt_store.set(pkgfmt_store.append(), 1, format, 2, False) + pkgfmt_tree = gtk.TreeView(pkgfmt_store) + pkgfmt_tree.set_headers_clickable(True) + pkgfmt_tree.set_headers_visible(False) + tree_selection = pkgfmt_tree.get_selection() + tree_selection.set_mode(gtk.SELECTION_SINGLE) + + col = gtk.TreeViewColumn('NO') + col.set_sort_column_id(0) + col.set_sort_order(gtk.SORT_ASCENDING) + col.set_clickable(False) + col1 = gtk.TreeViewColumn('TYPE') + col1.set_min_width(130) + col1.set_max_width(140) + col2 = gtk.TreeViewColumn('INCLUDED') + col2.set_min_width(60) + col2.set_max_width(70) + pkgfmt_tree.append_column(col1) + pkgfmt_tree.append_column(col2) + cell = gtk.CellRendererText() + cell1 = gtk.CellRendererText() + cell1.set_property('width-chars', 10) + cell2 = gtk.CellRendererToggle() + cell2.set_property('activatable', True) + cell2.connect("toggled", cls._toggle_cb, pkgfmt_store, 2) + col.pack_start(cell, True) + col1.pack_start(cell1, True) + col2.pack_end(cell2, True) + col.set_attributes(cell, text=0) + col1.set_attributes(cell1, text=1) + col2.set_attributes(cell2, active=2) + + pkgfmt_store.set_sort_func(0, cls._sort_func, None) + pkgfmt_store.set_sort_column_id(0, gtk.SORT_ASCENDING) + + scroll = gtk.ScrolledWindow() + scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + scroll.set_shadow_type(gtk.SHADOW_IN) + scroll.add(pkgfmt_tree) + scroll.set_size_request(200,60) + pkgfmt_hbox.pack_start(scroll, False, False, 0) + + vbox = gtk.VBox(False, 5) + pkgfmt_hbox.pack_start(vbox, False, False, 15) + + up = gtk.Button() + image = gtk.Image() + image.set_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_MENU) + up.set_image(image) + up.set_size_request(50,30) + up.connect("clicked", cls._pkgfmt_up_clicked_cb, tree_selection) + vbox.pack_start(up, False, False, 5) + + down = gtk.Button() + image = gtk.Image() + image.set_from_stock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_MENU) + down.set_image(image) + down.set_size_request(50,30) + down.connect("clicked", cls._pkgfmt_down_clicked_cb, tree_selection) + vbox.pack_start(down, False, False, 5) + tree_selection.connect("changed", cls._tree_selection_changed_cb, up, down) + + image = gtk.Image() + image.set_from_stock(gtk.STOCK_INFO, gtk.ICON_SIZE_BUTTON) + image.set_tooltip_text(tooltip) + pkgfmt_hbox.pack_start(image, expand=False, fill=False) + + pkgfmt_hbox.show_all() + + return pkgfmt_hbox, pkgfmt_store + + @classmethod + def gen_combo_widget(cls, curr_item, all_item, tooltip=""): + hbox = gtk.HBox(False, 10) + combo = gtk.combo_box_new_text() + hbox.pack_start(combo, expand=False, fill=False) + + index = 0 + for item in all_item or []: + combo.append_text(item) + if item == curr_item: + combo.set_active(index) + index += 1 + + image = gtk.Image() + image.show() + image.set_from_stock(gtk.STOCK_INFO, gtk.ICON_SIZE_BUTTON) + image.set_tooltip_text(tooltip) + + hbox.pack_start(image, expand=False, fill=False) + + hbox.show_all() + + return hbox, combo + + @classmethod + def gen_label_widget(cls, content): + label = gtk.Label() + label.set_alignment(0, 0) + label.set_markup(content) + label.show() + return label + + @classmethod + def _select_path_cb(cls, action, parent, entry): + dialog = gtk.FileChooserDialog("", parent, + gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, + (gtk.STOCK_OK, gtk.RESPONSE_YES, + gtk.STOCK_CANCEL, gtk.RESPONSE_NO)) + response = dialog.run() + if response == gtk.RESPONSE_YES: + path = dialog.get_filename() + entry.set_text(path) + + dialog.destroy() + + @classmethod + def gen_entry_widget(cls, split_model, content, parent, tooltip=""): + hbox = gtk.HBox(False, 10) + entry = gtk.Entry() + entry.set_text(content) + + if split_model: + hbox.pack_start(entry, expand=True, fill=True) + else: + table = gtk.Table(1, 10, True) + hbox.pack_start(table, expand=True, fill=True) + table.attach(entry, 0, 9, 0, 1) + image = gtk.Image() + image.set_from_stock(gtk.STOCK_OPEN,gtk.ICON_SIZE_BUTTON) + open_button = gtk.Button() + open_button.set_image(image) + open_button.connect("clicked", cls._select_path_cb, parent, entry) + table.attach(open_button, 9, 10, 0, 1) + + image = gtk.Image() + image.set_from_stock(gtk.STOCK_INFO, gtk.ICON_SIZE_BUTTON) + image.set_tooltip_text(tooltip) + hbox.pack_start(image, expand=False, fill=False) + + hbox.show_all() + + return hbox, entry + + @classmethod + def gen_spinner_widget(cls, content, lower, upper, tooltip=""): + hbox = gtk.HBox(False, 10) + adjust = gtk.Adjustment(value=content, lower=lower, upper=upper, step_incr=1) + spinner = gtk.SpinButton(adjustment=adjust, climb_rate=1, digits=0) + + spinner.set_value(content) + hbox.pack_start(spinner, expand=False, fill=False) + + image = gtk.Image() + image.set_from_stock(gtk.STOCK_INFO, gtk.ICON_SIZE_BUTTON) + image.set_tooltip_text(tooltip) + hbox.pack_start(image, expand=False, fill=False) + + hbox.show_all() + + return hbox, spinner + + @classmethod + def conf_error(cls, parent, lbl): + dialog = CrumbsDialog(parent, lbl) + dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) + response = dialog.run() + dialog.destroy() + + @classmethod + def _add_layer_cb(cls, action, layer_store, parent): + dialog = gtk.FileChooserDialog("Add new layer", parent, + gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, + (gtk.STOCK_OK, gtk.RESPONSE_YES, + gtk.STOCK_CANCEL, gtk.RESPONSE_NO)) + label = gtk.Label("Select the layer you wish to add") + label.show() + dialog.set_extra_widget(label) + response = dialog.run() + path = dialog.get_filename() + dialog.destroy() + + lbl = "Error\nUnable to load layer %s because " % path + if response == gtk.RESPONSE_YES: + import os + import os.path + layers = [] + it = layer_store.get_iter_first() + while it: + layers.append(layer_store.get_value(it, 0)) + it = layer_store.iter_next(it) + + if not path: + lbl += "it is an invalid path." + elif not os.path.exists(path+"/conf/layer.conf"): + lbl += "there is no layer.conf inside the directory." + elif path in layers: + lbl += "it is already in loaded layers." + else: + layer_store.append([path]) + return + cls.conf_error(parent, lbl) + + @classmethod + def _del_layer_cb(cls, action, tree_selection, layer_store): + model, iter = tree_selection.get_selected() + if iter: + layer_store.remove(iter) + + @classmethod + def _toggle_layer_cb(cls, cell, path, layer_store): + name = layer_store[path][0] + toggle = not layer_store[path][1] + layer_store[path][1] = toggle + + @classmethod + def gen_layer_widget(cls, split_model, layers, layers_avail, window, tooltip=""): + hbox = gtk.HBox(False, 10) + + layer_tv = gtk.TreeView() + 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) + + col0= gtk.TreeViewColumn('Path') + cell0 = gtk.CellRendererText() + cell0.set_padding(5,2) + col0.pack_start(cell0, True) + col0.set_attributes(cell0, text=0) + layer_tv.append_column(col0) + + scroll = gtk.ScrolledWindow() + scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + scroll.set_shadow_type(gtk.SHADOW_IN) + scroll.add(layer_tv) + + table_layer = gtk.Table(2, 10, False) + hbox.pack_start(table_layer, expand=True, fill=True) + + if split_model: + table_layer.attach(scroll, 0, 10, 0, 2) + + layer_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN) + for layer in layers: + layer_store.set(layer_store.append(), 0, layer, 1, True) + for layer in layers_avail: + if layer not in layers: + layer_store.set(layer_store.append(), 0, layer, 1, False) + + col1 = gtk.TreeViewColumn('Included') + layer_tv.append_column(col1) + + cell1 = gtk.CellRendererToggle() + cell1.connect("toggled", cls._toggle_layer_cb, layer_store) + col1.pack_start(cell1, True) + col1.set_attributes(cell1, active=1) + + else: + table_layer.attach(scroll, 0, 10, 0, 1) + + layer_store = gtk.ListStore(gobject.TYPE_STRING) + 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) + add_button.connect("clicked", cls._add_layer_cb, layer_store, window) + table_layer.attach(add_button, 0, 5, 1, 2, gtk.EXPAND | gtk.FILL, 0, 0, 0) + 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", cls._del_layer_cb, tree_selection, layer_store) + table_layer.attach(del_button, 5, 10, 1, 2, gtk.EXPAND | gtk.FILL, 0, 0, 0) + layer_tv.set_model(layer_store) + + hbox.show_all() + + return hbox, layer_store + + @classmethod + def _toggle_single_cb(cls, cell, select_path, treeview, toggle_column): + model = treeview.get_model() + if not model: + return + iter = model.get_iter_first() + while iter: + path = model.get_path(iter) + model[path][toggle_column] = False + iter = model.iter_next(iter) + + model[select_path][toggle_column] = True + + @classmethod + def gen_imgtv_widget(cls, col0_width, col1_width): + vbox = gtk.VBox(False, 10) + + imgsel_tv = gtk.TreeView() + imgsel_tv.set_rules_hint(True) + imgsel_tv.set_headers_visible(False) + tree_selection = imgsel_tv.get_selection() + tree_selection.set_mode(gtk.SELECTION_SINGLE) + + col0= gtk.TreeViewColumn('Image name') + cell0 = gtk.CellRendererText() + cell0.set_padding(5,2) + col0.pack_start(cell0, True) + col0.set_attributes(cell0, text=0) + col0.set_max_width(col0_width) + col0.set_min_width(col0_width) + imgsel_tv.append_column(col0) + + col1= gtk.TreeViewColumn('Select') + cell1 = gtk.CellRendererToggle() + cell1.set_padding(5,2) + cell1.connect("toggled", cls._toggle_single_cb, imgsel_tv, 1) + col1.pack_start(cell1, True) + col1.set_attributes(cell1, active=1) + col1.set_max_width(col1_width) + col1.set_min_width(col1_width) + imgsel_tv.append_column(col1) + + scroll = gtk.ScrolledWindow() + scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + scroll.set_shadow_type(gtk.SHADOW_IN) + scroll.add(imgsel_tv) + + vbox.pack_start(scroll, expand=True, fill=True) + + return vbox, imgsel_tv + + @classmethod + def gen_images_widget(cls, col0_width, col1_width, col2_width): + vbox = gtk.VBox(False, 10) + + imgsel_tv = gtk.TreeView() + imgsel_tv.set_rules_hint(True) + imgsel_tv.set_headers_visible(False) + tree_selection = imgsel_tv.get_selection() + tree_selection.set_mode(gtk.SELECTION_SINGLE) + + col0= gtk.TreeViewColumn('Image name') + cell0 = gtk.CellRendererText() + cell0.set_padding(5,2) + col0.pack_start(cell0, True) + col0.set_attributes(cell0, text=0) + col0.set_max_width(col0_width) + col0.set_min_width(col0_width) + imgsel_tv.append_column(col0) + + col1= gtk.TreeViewColumn('Image size') + cell1 = gtk.CellRendererText() + cell1.set_padding(5,2) + col1.pack_start(cell1, True) + col1.set_attributes(cell1, text=1) + col1.set_max_width(col1_width) + col1.set_min_width(col1_width) + imgsel_tv.append_column(col1) + + col2= gtk.TreeViewColumn('Select') + cell2 = gtk.CellRendererToggle() + cell2.set_padding(5,2) + cell2.connect("toggled", cls._toggle_single_cb, imgsel_tv, 2) + col2.pack_start(cell2, True) + col2.set_attributes(cell2, active=2) + col2.set_max_width(col2_width) + col2.set_min_width(col2_width) + imgsel_tv.append_column(col2) + + scroll = gtk.ScrolledWindow() + scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + scroll.set_shadow_type(gtk.SHADOW_IN) + scroll.add(imgsel_tv) + + vbox.pack_start(scroll, expand=True, fill=True) + + return vbox, imgsel_tv + + @classmethod + def _on_add_item_clicked(cls, button, model): + new_item = ["##KEY##", "##VALUE##"] + + iter = model.append() + model.set (iter, + 0, new_item[0], + 1, new_item[1], + ) + + + @classmethod + def _on_remove_item_clicked(cls, button, treeview): + + selection = treeview.get_selection() + model, iter = selection.get_selected() + + if iter: + path = model.get_path(iter)[0] + model.remove(iter) + + @classmethod + def _on_cell_edited(cls, cell, path_string, new_text, model): + it = model.get_iter_from_string(path_string) + column = cell.get_data("column") + model.set(it, column, new_text) + + + @classmethod + def gen_editable_settings(cls, setting, tooltip=""): + setting_hbox = gtk.HBox(False, 10) + + vbox = gtk.VBox(False, 10) + setting_hbox.pack_start(vbox, expand=True, fill=True) + + setting_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) + for key in setting.keys(): + setting_store.set(setting_store.append(), 0, key, 1, setting[key]) + + setting_tree = gtk.TreeView(setting_store) + setting_tree.set_headers_visible(True) + setting_tree.set_size_request(300, 100) + + col = gtk.TreeViewColumn('Key') + col.set_min_width(100) + col.set_max_width(150) + col.set_resizable(True) + col1 = gtk.TreeViewColumn('Value') + col1.set_min_width(100) + col1.set_max_width(150) + col1.set_resizable(True) + setting_tree.append_column(col) + setting_tree.append_column(col1) + cell = gtk.CellRendererText() + cell.set_property('width-chars', 10) + cell.set_property('editable', True) + cell.set_data("column", 0) + cell.connect("edited", cls._on_cell_edited, setting_store) + cell1 = gtk.CellRendererText() + cell1.set_property('width-chars', 10) + cell1.set_property('editable', True) + cell1.set_data("column", 1) + cell1.connect("edited", cls._on_cell_edited, setting_store) + col.pack_start(cell, True) + col1.pack_end(cell1, True) + col.set_attributes(cell, text=0) + col1.set_attributes(cell1, text=1) + + scroll = gtk.ScrolledWindow() + scroll.set_shadow_type(gtk.SHADOW_IN) + scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + scroll.add(setting_tree) + vbox.pack_start(scroll, expand=True, fill=True) + + # some buttons + hbox = gtk.HBox(True, 4) + vbox.pack_start(hbox, False, False) + + button = gtk.Button(stock=gtk.STOCK_ADD) + button.connect("clicked", cls._on_add_item_clicked, setting_store) + hbox.pack_start(button) + + button = gtk.Button(stock=gtk.STOCK_REMOVE) + button.connect("clicked", cls._on_remove_item_clicked, setting_tree) + hbox.pack_start(button) + + image = gtk.Image() + image.set_from_stock(gtk.STOCK_INFO, gtk.ICON_SIZE_BUTTON) + image.set_tooltip_text(tooltip) + setting_hbox.pack_start(image, expand=False, fill=False) + + return setting_hbox, setting_store + +class HobViewTable (gtk.VBox): + """ + A VBox to contain the table for different recipe views and package view + """ + def __init__(self, columns, reset_clicked_cb=None, toggled_cb=None): + gtk.VBox.__init__(self, False, 6) + self.table_tree = gtk.TreeView() + self.table_tree.set_headers_visible(True) + self.table_tree.set_headers_clickable(True) + self.table_tree.set_enable_search(True) + self.table_tree.set_search_column(0) + self.table_tree.get_selection().set_mode(gtk.SELECTION_SINGLE) + + for i in range(len(columns)): + col = gtk.TreeViewColumn(columns[i]['col_name']) + col.set_clickable(True) + col.set_resizable(True) + col.set_sort_column_id(columns[i]['col_id']) + col.set_min_width(columns[i]['col_min']) + col.set_max_width(columns[i]['col_max']) + self.table_tree.append_column(col) + + if columns[i]['col_style'] == 'toggle': + cell = gtk.CellRendererToggle() + cell.set_property('activatable', True) + cell.connect("toggled", toggled_cb, self.table_tree) + col.pack_end(cell, True) + col.set_attributes(cell, active=columns[i]['col_id']) + elif columns[i]['col_style'] == 'text': + cell = gtk.CellRendererText() + col.pack_start(cell, True) + col.set_attributes(cell, text=columns[i]['col_id']) + + scroll = gtk.ScrolledWindow() + scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) + scroll.set_shadow_type(gtk.SHADOW_IN) + scroll.add(self.table_tree) + self.pack_start(scroll, True, True, 0) + + hbox = gtk.HBox(False, 5) + button = gtk.Button("Reset") + button.connect('clicked', reset_clicked_cb) + hbox.pack_end(button, False, False, 0) + + self.pack_start(hbox, False, False, 0) + +class HobViewBar (gtk.EventBox): + """ + A EventBox with the specified gray background color is associated with a notebook. + And the toolbar to simulate the tabs. + """ + + def __init__(self, notebook): + if not notebook: + return + self.notebook = notebook + + # setup an event box + gtk.EventBox.__init__(self) + self.set_border_width(2) + style = self.get_style().copy() + style.bg[gtk.STATE_NORMAL] = self.get_colormap().alloc_color (HobColors.GRAY, False, False) + self.set_style(style) + + hbox = gtk.HBox() + self.add(hbox) + + # setup a tool bar in the event box + self.toolbar = gtk.Toolbar() + self.toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL) + self.toolbar.set_style(gtk.TOOLBAR_TEXT) + self.toolbar.set_border_width(5) + + self.toolbuttons = [] + for index in range(self.notebook.get_n_pages()): + child = self.notebook.get_nth_page(index) + label = self.notebook.get_tab_label_text(child) + tip_text = 'switch to ' + label + ' page' + toolbutton = self.toolbar.append_element(gtk.TOOLBAR_CHILD_RADIOBUTTON, None, + label, tip_text, "Private text", None, + self.toolbutton_cb, index) + toolbutton.set_size_request(200, 100) + self.toolbuttons.append(toolbutton) + + # set the default current page + self.modify_toolbuttons_bg(0) + self.notebook.set_current_page(0) + + self.toolbar.append_space() + + # add the tool bar into the event box + hbox.pack_start(self.toolbar, expand=False, fill=False) + + self.search = gtk.Entry() + self.align = gtk.Alignment(xalign=0.5, yalign=0.5) + self.align.add(self.search) + hbox.pack_end(self.align, expand=False, fill=False) + + self.label = gtk.Label(" Search: ") + self.label.set_alignment(0.5, 0.5) + hbox.pack_end(self.label, expand=False, fill=False) + + def toolbutton_cb(self, widget, index): + if index >= self.notebook.get_n_pages(): + return + self.notebook.set_current_page(index) + self.modify_toolbuttons_bg(index) + + def modify_toolbuttons_bg(self, index): + if index >= len(self.toolbuttons): + return + for i in range(0, len(self.toolbuttons)): + toolbutton = self.toolbuttons[i] + if i == index: + self.modify_toolbutton_bg(toolbutton, True) + else: + self.modify_toolbutton_bg(toolbutton) + + def modify_toolbutton_bg(self, toolbutton, active=False): + if active: + toolbutton.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(HobColors.WHITE)) + toolbutton.modify_bg(gtk.STATE_ACTIVE, gtk.gdk.Color(HobColors.WHITE)) + toolbutton.modify_bg(gtk.STATE_SELECTED, gtk.gdk.Color(HobColors.WHITE)) + toolbutton.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(HobColors.WHITE)) + else: + toolbutton.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(HobColors.GRAY)) + toolbutton.modify_bg(gtk.STATE_ACTIVE, gtk.gdk.Color(HobColors.GRAY)) + toolbutton.modify_bg(gtk.STATE_SELECTED, gtk.gdk.Color(HobColors.GRAY)) + toolbutton.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(HobColors.GRAY)) + +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 + 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("%s" % label) + self.tb.attach(lbl, 2, 10, 0, 1) + + lbl = gtk.Label() + lbl.set_alignment(0.0, 0.5) + lbl.set_markup("%s" % 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 + -- cgit v1.2.3-54-g00ecf