2011-11-28 06:32:40 +00:00
|
|
|
# BitBake Graphical GTK User Interface
|
|
|
|
#
|
|
|
|
# Copyright (C) 2011-2012 Intel Corporation
|
|
|
|
#
|
|
|
|
# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
|
|
|
|
# Authored by Shane Wang <shane.wang@intel.com>
|
|
|
|
#
|
|
|
|
# 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
|
Hob: implement a self-defined notebook visual component for Hob
In recipe selection page, package selection page, and build details page, etc, there is a notebook component which is not gtk.Notebook in the design video.
We implement the visual component with a drawing area, and use it to replace the old notebook in recipe selection page and package selection page. The reasons why we do it are:
1) General speaking, gtk.Notebook doesn't look like the designer worked out. (see https://wiki.yoctoproject.org/wiki/File:Hob1.2-screencast2.mov)
2) And the designer version looks better, for example, there is an indicator to show how many recipes or packages are included, and how many issues happened when building? Very straightforward.
But technically, gtk.Notebook can't implement that, as far as we know.
3) Moreover, there is an entry for "search recipes", and "search packages". How to make it horizontal to the tabs is a problem to us.
Regarding those, we give up gtk.Notebook and use our own.
(From Poky rev: e4ebac226cc5e4589bcecd8bada9fde462e925cc)
(Bitbake rev: b0c2ca3f600694c6d37924006de3f9474b2a9a8e)
Signed-off-by: Liming An <limingx.l.an@intel.com>
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-27 05:28:26 +00:00
|
|
|
import sys
|
|
|
|
import pango, pangocairo
|
2012-04-12 19:43:12 +00:00
|
|
|
import cairo
|
Hob: implement a self-defined notebook visual component for Hob
In recipe selection page, package selection page, and build details page, etc, there is a notebook component which is not gtk.Notebook in the design video.
We implement the visual component with a drawing area, and use it to replace the old notebook in recipe selection page and package selection page. The reasons why we do it are:
1) General speaking, gtk.Notebook doesn't look like the designer worked out. (see https://wiki.yoctoproject.org/wiki/File:Hob1.2-screencast2.mov)
2) And the designer version looks better, for example, there is an indicator to show how many recipes or packages are included, and how many issues happened when building? Very straightforward.
But technically, gtk.Notebook can't implement that, as far as we know.
3) Moreover, there is an entry for "search recipes", and "search packages". How to make it horizontal to the tabs is a problem to us.
Regarding those, we give up gtk.Notebook and use our own.
(From Poky rev: e4ebac226cc5e4589bcecd8bada9fde462e925cc)
(Bitbake rev: b0c2ca3f600694c6d37924006de3f9474b2a9a8e)
Signed-off-by: Liming An <limingx.l.an@intel.com>
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-27 05:28:26 +00:00
|
|
|
import math
|
|
|
|
|
2011-11-28 06:32:40 +00:00
|
|
|
from bb.ui.crumbs.hobcolor import HobColors
|
2012-03-02 23:41:21 +00:00
|
|
|
from bb.ui.crumbs.persistenttooltip import PersistentTooltip
|
2011-11-28 06:32:40 +00:00
|
|
|
|
|
|
|
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'))
|
2012-03-29 12:54:56 +00:00
|
|
|
ICON_INDI_ERROR_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/denied.png'))
|
2012-03-22 22:54:37 +00:00
|
|
|
ICON_INDI_REMOVE_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/remove.png'))
|
|
|
|
ICON_INDI_REMOVE_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/remove-hover.png'))
|
|
|
|
ICON_INDI_ADD_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/add.png'))
|
|
|
|
ICON_INDI_ADD_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/add-hover.png'))
|
2012-03-23 14:29:46 +00:00
|
|
|
ICON_INDI_REFRESH_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/refresh.png'))
|
2012-03-23 15:32:17 +00:00
|
|
|
ICON_INDI_ALERT_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/alert.png'))
|
|
|
|
ICON_INDI_TICK_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/tick.png'))
|
2012-04-02 15:22:37 +00:00
|
|
|
ICON_INDI_INFO_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/info.png'))
|
2011-11-28 06:32:40 +00:00
|
|
|
|
|
|
|
class HobViewTable (gtk.VBox):
|
|
|
|
"""
|
|
|
|
A VBox to contain the table for different recipe views and package view
|
|
|
|
"""
|
2012-02-29 14:14:58 +00:00
|
|
|
__gsignals__ = {
|
2012-02-29 14:15:01 +00:00
|
|
|
"toggled" : (gobject.SIGNAL_RUN_LAST,
|
|
|
|
gobject.TYPE_NONE,
|
|
|
|
(gobject.TYPE_PYOBJECT,
|
|
|
|
gobject.TYPE_STRING,
|
|
|
|
gobject.TYPE_INT,
|
|
|
|
gobject.TYPE_PYOBJECT,)),
|
|
|
|
"row-activated" : (gobject.SIGNAL_RUN_LAST,
|
|
|
|
gobject.TYPE_NONE,
|
|
|
|
(gobject.TYPE_PYOBJECT,
|
|
|
|
gobject.TYPE_PYOBJECT,)),
|
2012-04-09 14:13:32 +00:00
|
|
|
"cell-fadeinout-stopped" : (gobject.SIGNAL_RUN_LAST,
|
|
|
|
gobject.TYPE_NONE,
|
|
|
|
(gobject.TYPE_PYOBJECT,
|
|
|
|
gobject.TYPE_PYOBJECT,
|
|
|
|
gobject.TYPE_PYOBJECT,)),
|
2012-02-29 14:14:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self, columns):
|
2011-11-28 06:32:40 +00:00
|
|
|
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)
|
2012-02-29 14:14:58 +00:00
|
|
|
self.table_tree.set_rules_hint(True)
|
2012-05-08 11:48:07 +00:00
|
|
|
self.table_tree.set_enable_tree_lines(True)
|
2011-11-28 06:32:40 +00:00
|
|
|
self.table_tree.get_selection().set_mode(gtk.SELECTION_SINGLE)
|
2012-02-29 14:15:01 +00:00
|
|
|
self.toggle_columns = []
|
|
|
|
self.table_tree.connect("row-activated", self.row_activated_cb)
|
2011-11-28 06:32:40 +00:00
|
|
|
|
2012-03-16 05:40:41 +00:00
|
|
|
for i, column in enumerate(columns):
|
|
|
|
col = gtk.TreeViewColumn(column['col_name'])
|
2011-11-28 06:32:40 +00:00
|
|
|
col.set_clickable(True)
|
|
|
|
col.set_resizable(True)
|
2012-03-16 05:40:41 +00:00
|
|
|
col.set_sort_column_id(column['col_id'])
|
|
|
|
if 'col_min' in column.keys():
|
|
|
|
col.set_min_width(column['col_min'])
|
|
|
|
if 'col_max' in column.keys():
|
|
|
|
col.set_max_width(column['col_max'])
|
2012-04-06 23:02:22 +00:00
|
|
|
if 'expand' in column.keys():
|
|
|
|
col.set_expand(True)
|
2011-11-28 06:32:40 +00:00
|
|
|
self.table_tree.append_column(col)
|
|
|
|
|
2012-03-16 05:40:41 +00:00
|
|
|
if (not 'col_style' in column.keys()) or column['col_style'] == 'text':
|
2012-02-29 14:14:58 +00:00
|
|
|
cell = gtk.CellRendererText()
|
|
|
|
col.pack_start(cell, True)
|
2012-03-16 05:40:41 +00:00
|
|
|
col.set_attributes(cell, text=column['col_id'])
|
2012-05-08 11:48:07 +00:00
|
|
|
if 'col_t_id' in column.keys():
|
|
|
|
col.add_attribute(cell, 'font', column['col_t_id'])
|
2012-03-16 05:40:41 +00:00
|
|
|
elif column['col_style'] == 'check toggle':
|
2012-04-09 14:13:32 +00:00
|
|
|
cell = HobCellRendererToggle()
|
2011-11-28 06:32:40 +00:00
|
|
|
cell.set_property('activatable', True)
|
2012-02-29 14:14:58 +00:00
|
|
|
cell.connect("toggled", self.toggled_cb, i, self.table_tree)
|
2012-04-09 14:13:32 +00:00
|
|
|
cell.connect_render_state_changed(self.stop_cell_fadeinout_cb, self.table_tree)
|
2012-02-29 14:14:58 +00:00
|
|
|
self.toggle_id = i
|
|
|
|
col.pack_end(cell, True)
|
2012-03-16 05:40:41 +00:00
|
|
|
col.set_attributes(cell, active=column['col_id'])
|
|
|
|
self.toggle_columns.append(column['col_name'])
|
2012-05-08 11:48:07 +00:00
|
|
|
if 'col_group' in column.keys():
|
|
|
|
col.set_cell_data_func(cell, self.set_group_number_cb)
|
2012-03-16 05:40:41 +00:00
|
|
|
elif column['col_style'] == 'radio toggle':
|
2012-02-29 14:14:58 +00:00
|
|
|
cell = gtk.CellRendererToggle()
|
|
|
|
cell.set_property('activatable', True)
|
|
|
|
cell.set_radio(True)
|
|
|
|
cell.connect("toggled", self.toggled_cb, i, self.table_tree)
|
|
|
|
self.toggle_id = i
|
2011-11-28 06:32:40 +00:00
|
|
|
col.pack_end(cell, True)
|
2012-03-16 05:40:41 +00:00
|
|
|
col.set_attributes(cell, active=column['col_id'])
|
|
|
|
self.toggle_columns.append(column['col_name'])
|
2012-04-05 21:39:50 +00:00
|
|
|
elif column['col_style'] == 'binb':
|
|
|
|
cell = gtk.CellRendererText()
|
|
|
|
col.pack_start(cell, True)
|
|
|
|
col.set_cell_data_func(cell, self.display_binb_cb, column['col_id'])
|
2012-05-08 11:48:07 +00:00
|
|
|
if 'col_t_id' in column.keys():
|
|
|
|
col.add_attribute(cell, 'font', column['col_t_id'])
|
2011-11-28 06:32:40 +00:00
|
|
|
|
|
|
|
scroll = gtk.ScrolledWindow()
|
|
|
|
scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
|
|
|
|
scroll.add(self.table_tree)
|
|
|
|
self.pack_start(scroll, True, True, 0)
|
|
|
|
|
2012-04-05 21:39:50 +00:00
|
|
|
def display_binb_cb(self, col, cell, model, it, col_id):
|
|
|
|
binb = model.get_value(it, col_id)
|
|
|
|
# Just display the first item
|
|
|
|
if binb:
|
|
|
|
bin = binb.split(', ')
|
2012-09-05 11:13:48 +00:00
|
|
|
total_no = len(bin)
|
|
|
|
if total_no > 1 and bin[0] == "User Selected":
|
2012-10-16 08:52:38 +00:00
|
|
|
if total_no > 2:
|
|
|
|
present_binb = bin[1] + ' (+' + str(total_no - 1) + ')'
|
|
|
|
else:
|
|
|
|
present_binb = bin[1]
|
2012-09-05 11:13:48 +00:00
|
|
|
else:
|
2012-10-16 08:52:38 +00:00
|
|
|
if total_no > 1:
|
|
|
|
present_binb = bin[0] + ' (+' + str(total_no - 1) + ')'
|
|
|
|
else:
|
|
|
|
present_binb = bin[0]
|
2012-09-05 11:13:48 +00:00
|
|
|
cell.set_property('text', present_binb)
|
2012-04-16 10:09:48 +00:00
|
|
|
else:
|
|
|
|
cell.set_property('text', "")
|
2012-04-05 21:39:50 +00:00
|
|
|
return True
|
|
|
|
|
2012-02-29 14:14:58 +00:00
|
|
|
def set_model(self, tree_model):
|
|
|
|
self.table_tree.set_model(tree_model)
|
|
|
|
|
|
|
|
def set_search_entry(self, search_column_id, entry):
|
|
|
|
self.table_tree.set_search_column(search_column_id)
|
|
|
|
self.table_tree.set_search_entry(entry)
|
|
|
|
|
|
|
|
def toggle_default(self):
|
|
|
|
model = self.table_tree.get_model()
|
|
|
|
if not model:
|
|
|
|
return
|
|
|
|
iter = model.get_iter_first()
|
|
|
|
if iter:
|
|
|
|
rowpath = model.get_path(iter)
|
|
|
|
model[rowpath][self.toggle_id] = True
|
|
|
|
|
|
|
|
def toggled_cb(self, cell, path, columnid, tree):
|
|
|
|
self.emit("toggled", cell, path, columnid, tree)
|
2011-11-28 06:32:40 +00:00
|
|
|
|
2012-02-29 14:15:01 +00:00
|
|
|
def row_activated_cb(self, tree, path, view_column):
|
|
|
|
if not view_column.get_title() in self.toggle_columns:
|
|
|
|
self.emit("row-activated", tree.get_model(), path)
|
2011-11-28 06:32:40 +00:00
|
|
|
|
2012-04-09 14:13:32 +00:00
|
|
|
def stop_cell_fadeinout_cb(self, ctrl, cell, tree):
|
|
|
|
self.emit("cell-fadeinout-stopped", ctrl, cell, tree)
|
|
|
|
|
2012-05-08 11:48:07 +00:00
|
|
|
def set_group_number_cb(self, col, cell, model, iter):
|
|
|
|
if model and (model.iter_parent(iter) == None):
|
|
|
|
cell.cell_attr["number_of_children"] = model.iter_n_children(iter)
|
|
|
|
else:
|
|
|
|
cell.cell_attr["number_of_children"] = 0
|
|
|
|
|
|
|
|
def connect_group_selection(self, cb_func):
|
|
|
|
self.table_tree.get_selection().connect("changed", cb_func)
|
|
|
|
|
2012-03-22 22:54:37 +00:00
|
|
|
"""
|
|
|
|
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.7
|
|
|
|
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()
|
|
|
|
|
2012-09-03 09:51:06 +00:00
|
|
|
class BaseHobButton(gtk.Button):
|
2012-03-22 23:05:42 +00:00
|
|
|
"""
|
|
|
|
A gtk.Button subclass which follows the visual design of Hob for primary
|
|
|
|
action buttons
|
|
|
|
|
|
|
|
label: the text to display as the button's label
|
|
|
|
"""
|
|
|
|
def __init__(self, label):
|
2012-03-24 00:23:03 +00:00
|
|
|
gtk.Button.__init__(self, label)
|
|
|
|
HobButton.style_button(self)
|
2012-03-22 23:05:42 +00:00
|
|
|
|
2012-03-24 00:23:03 +00:00
|
|
|
@staticmethod
|
|
|
|
def style_button(button):
|
|
|
|
style = button.get_style()
|
2012-09-03 09:51:06 +00:00
|
|
|
style = gtk.rc_get_style_by_paths(gtk.settings_get_default(), 'gtk-button', 'gtk-button', gobject.TYPE_NONE)
|
2012-03-22 23:05:42 +00:00
|
|
|
|
2012-03-24 00:23:03 +00:00
|
|
|
button.set_flags(gtk.CAN_DEFAULT)
|
|
|
|
button.grab_default()
|
|
|
|
|
2012-09-03 09:51:06 +00:00
|
|
|
# label = "<span size='x-large'><b>%s</b></span>" % gobject.markup_escape_text(button.get_label())
|
|
|
|
label = button.get_label()
|
2012-03-24 00:23:03 +00:00
|
|
|
button.set_label(label)
|
|
|
|
button.child.set_use_markup(True)
|
2012-03-22 23:05:42 +00:00
|
|
|
|
2012-09-03 09:51:06 +00:00
|
|
|
class HobButton(BaseHobButton):
|
|
|
|
"""
|
|
|
|
A gtk.Button subclass which follows the visual design of Hob for primary
|
|
|
|
action buttons
|
|
|
|
|
|
|
|
label: the text to display as the button's label
|
|
|
|
"""
|
|
|
|
def __init__(self, label):
|
|
|
|
BaseHobButton.__init__(self, label)
|
|
|
|
HobButton.style_button(self)
|
|
|
|
|
|
|
|
class HobAltButton(BaseHobButton):
|
2012-03-22 01:42:35 +00:00
|
|
|
"""
|
|
|
|
A gtk.Button subclass which has no relief, and so is more discrete
|
|
|
|
"""
|
2012-03-22 23:02:00 +00:00
|
|
|
def __init__(self, label):
|
2012-09-03 09:51:06 +00:00
|
|
|
BaseHobButton.__init__(self, label)
|
2012-03-24 00:23:03 +00:00
|
|
|
HobAltButton.style_button(self)
|
2012-03-24 00:23:00 +00:00
|
|
|
|
|
|
|
"""
|
|
|
|
A callback for the state-changed event to ensure the text is displayed
|
|
|
|
differently when the widget is not sensitive
|
|
|
|
"""
|
2012-03-24 00:23:03 +00:00
|
|
|
@staticmethod
|
|
|
|
def desensitise_on_state_change_cb(button, state):
|
2012-04-05 17:17:57 +00:00
|
|
|
if not button.get_property("sensitive"):
|
2012-03-24 00:23:03 +00:00
|
|
|
HobAltButton.set_text(button, False)
|
2012-03-24 00:23:00 +00:00
|
|
|
else:
|
2012-03-24 00:23:03 +00:00
|
|
|
HobAltButton.set_text(button, True)
|
2012-03-24 00:23:00 +00:00
|
|
|
|
|
|
|
"""
|
|
|
|
Set the button label with an appropriate colour for the current widget state
|
|
|
|
"""
|
2012-03-24 00:23:03 +00:00
|
|
|
@staticmethod
|
|
|
|
def set_text(button, sensitive=True):
|
2012-03-24 00:23:00 +00:00
|
|
|
if sensitive:
|
|
|
|
colour = HobColors.PALE_BLUE
|
|
|
|
else:
|
|
|
|
colour = HobColors.LIGHT_GRAY
|
2012-03-28 23:32:28 +00:00
|
|
|
button.set_label("<span size='large' color='%s'><b>%s</b></span>" % (colour, gobject.markup_escape_text(button.text)))
|
2012-03-24 00:23:03 +00:00
|
|
|
button.child.set_use_markup(True)
|
|
|
|
|
2012-03-22 22:54:37 +00:00
|
|
|
class HobImageButton(gtk.Button):
|
2011-11-28 06:32:40 +00:00
|
|
|
"""
|
2012-03-22 22:54:37 +00:00
|
|
|
A gtk.Button 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="", hover_icon_path=""):
|
|
|
|
gtk.Button.__init__(self)
|
|
|
|
self.set_relief(gtk.RELIEF_NONE)
|
|
|
|
|
|
|
|
self.icon_path = icon_path
|
|
|
|
self.hover_icon_path = hover_icon_path
|
|
|
|
|
2012-03-28 23:32:28 +00:00
|
|
|
hbox = gtk.HBox(False, 10)
|
2012-03-22 22:54:37 +00:00
|
|
|
hbox.show()
|
|
|
|
self.add(hbox)
|
|
|
|
self.icon = gtk.Image()
|
|
|
|
self.icon.set_from_file(self.icon_path)
|
|
|
|
self.icon.set_alignment(0.5, 0.0)
|
|
|
|
self.icon.show()
|
|
|
|
if self.hover_icon_path and len(self.hover_icon_path):
|
|
|
|
self.connect("enter-notify-event", self.set_hover_icon_cb)
|
|
|
|
self.connect("leave-notify-event", self.set_icon_cb)
|
|
|
|
hbox.pack_start(self.icon, False, False, 0)
|
|
|
|
label = gtk.Label()
|
|
|
|
label.set_alignment(0.0, 0.5)
|
|
|
|
colour = soften_color(label)
|
2012-03-28 23:32:28 +00:00
|
|
|
mark = "<span size='x-large'>%s</span>\n<span size='medium' fgcolor='%s' weight='ultralight'>%s</span>" % (primary_text, colour, secondary_text)
|
2012-03-22 22:54:37 +00:00
|
|
|
label.set_markup(mark)
|
|
|
|
label.show()
|
2012-03-28 23:32:28 +00:00
|
|
|
hbox.pack_start(label, True, True, 0)
|
2012-03-22 22:54:37 +00:00
|
|
|
|
|
|
|
def set_hover_icon_cb(self, widget, event):
|
|
|
|
self.icon.set_from_file(self.hover_icon_path)
|
|
|
|
|
|
|
|
def set_icon_cb(self, widget, event):
|
|
|
|
self.icon.set_from_file(self.icon_path)
|
2011-11-28 06:32:40 +00:00
|
|
|
|
2012-03-02 23:41:21 +00:00
|
|
|
class HobInfoButton(gtk.EventBox):
|
|
|
|
"""
|
|
|
|
This class implements a button-like widget per the Hob visual and UX designs
|
|
|
|
which will display a persistent tooltip, with the contents of tip_markup, when
|
|
|
|
clicked.
|
|
|
|
|
|
|
|
tip_markup: the Pango Markup to be displayed in the persistent tooltip
|
|
|
|
"""
|
|
|
|
def __init__(self, tip_markup, parent=None):
|
|
|
|
gtk.EventBox.__init__(self)
|
|
|
|
self.image = gtk.Image()
|
2012-09-03 09:51:06 +00:00
|
|
|
self.image.set_from_file(
|
|
|
|
hic.ICON_INFO_DISPLAY_FILE)
|
2012-03-02 23:41:21 +00:00
|
|
|
self.image.show()
|
|
|
|
self.add(self.image)
|
|
|
|
|
|
|
|
self.set_events(gtk.gdk.BUTTON_RELEASE |
|
|
|
|
gtk.gdk.ENTER_NOTIFY_MASK |
|
|
|
|
gtk.gdk.LEAVE_NOTIFY_MASK)
|
|
|
|
|
|
|
|
self.ptip = PersistentTooltip(tip_markup)
|
|
|
|
|
|
|
|
if parent:
|
|
|
|
self.ptip.set_parent(parent)
|
|
|
|
self.ptip.set_transient_for(parent)
|
|
|
|
self.ptip.set_destroy_with_parent(True)
|
|
|
|
|
|
|
|
self.connect("button-release-event", self.button_release_cb)
|
|
|
|
self.connect("enter-notify-event", self.mouse_in_cb)
|
|
|
|
self.connect("leave-notify-event", self.mouse_out_cb)
|
|
|
|
|
|
|
|
"""
|
|
|
|
When the mouse click is released emulate a button-click and show the associated
|
|
|
|
PersistentTooltip
|
|
|
|
"""
|
|
|
|
def button_release_cb(self, widget, event):
|
|
|
|
self.ptip.show()
|
|
|
|
|
|
|
|
"""
|
|
|
|
Change to the prelight image when the mouse enters the widget
|
|
|
|
"""
|
|
|
|
def mouse_in_cb(self, widget, event):
|
|
|
|
self.image.set_from_file(hic.ICON_INFO_HOVER_FILE)
|
|
|
|
|
|
|
|
"""
|
|
|
|
Change to the stock image when the mouse enters the widget
|
|
|
|
"""
|
|
|
|
def mouse_out_cb(self, widget, event):
|
|
|
|
self.image.set_from_file(hic.ICON_INFO_DISPLAY_FILE)
|
Hob: implement a self-defined notebook visual component for Hob
In recipe selection page, package selection page, and build details page, etc, there is a notebook component which is not gtk.Notebook in the design video.
We implement the visual component with a drawing area, and use it to replace the old notebook in recipe selection page and package selection page. The reasons why we do it are:
1) General speaking, gtk.Notebook doesn't look like the designer worked out. (see https://wiki.yoctoproject.org/wiki/File:Hob1.2-screencast2.mov)
2) And the designer version looks better, for example, there is an indicator to show how many recipes or packages are included, and how many issues happened when building? Very straightforward.
But technically, gtk.Notebook can't implement that, as far as we know.
3) Moreover, there is an entry for "search recipes", and "search packages". How to make it horizontal to the tabs is a problem to us.
Regarding those, we give up gtk.Notebook and use our own.
(From Poky rev: e4ebac226cc5e4589bcecd8bada9fde462e925cc)
(Bitbake rev: b0c2ca3f600694c6d37924006de3f9474b2a9a8e)
Signed-off-by: Liming An <limingx.l.an@intel.com>
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-27 05:28:26 +00:00
|
|
|
|
2012-04-12 19:43:12 +00:00
|
|
|
class HobIndicator(gtk.DrawingArea):
|
|
|
|
def __init__(self, count):
|
Hob: implement a self-defined notebook visual component for Hob
In recipe selection page, package selection page, and build details page, etc, there is a notebook component which is not gtk.Notebook in the design video.
We implement the visual component with a drawing area, and use it to replace the old notebook in recipe selection page and package selection page. The reasons why we do it are:
1) General speaking, gtk.Notebook doesn't look like the designer worked out. (see https://wiki.yoctoproject.org/wiki/File:Hob1.2-screencast2.mov)
2) And the designer version looks better, for example, there is an indicator to show how many recipes or packages are included, and how many issues happened when building? Very straightforward.
But technically, gtk.Notebook can't implement that, as far as we know.
3) Moreover, there is an entry for "search recipes", and "search packages". How to make it horizontal to the tabs is a problem to us.
Regarding those, we give up gtk.Notebook and use our own.
(From Poky rev: e4ebac226cc5e4589bcecd8bada9fde462e925cc)
(Bitbake rev: b0c2ca3f600694c6d37924006de3f9474b2a9a8e)
Signed-off-by: Liming An <limingx.l.an@intel.com>
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-27 05:28:26 +00:00
|
|
|
gtk.DrawingArea.__init__(self)
|
2012-05-30 12:01:10 +00:00
|
|
|
# Set no window for transparent background
|
|
|
|
self.set_has_window(False)
|
2012-04-12 19:43:12 +00:00
|
|
|
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.connect('expose-event', self.expose)
|
|
|
|
|
|
|
|
self.count = count
|
|
|
|
self.color = HobColors.GRAY
|
|
|
|
|
|
|
|
def expose(self, widget, event):
|
|
|
|
if self.count and self.count > 0:
|
2012-05-30 12:01:10 +00:00
|
|
|
ctx = widget.window.cairo_create()
|
|
|
|
|
|
|
|
x, y, w, h = self.allocation
|
2012-04-12 19:43:12 +00:00
|
|
|
|
|
|
|
ctx.set_operator(cairo.OPERATOR_OVER)
|
|
|
|
ctx.set_source_color(gtk.gdk.color_parse(self.color))
|
|
|
|
ctx.translate(w/2, h/2)
|
2012-05-30 12:01:10 +00:00
|
|
|
ctx.arc(x, y, min(w,h)/2 - 2, 0, 2*math.pi)
|
2012-04-12 19:43:12 +00:00
|
|
|
ctx.fill_preserve()
|
|
|
|
|
|
|
|
layout = self.create_pango_layout(str(self.count))
|
|
|
|
textw, texth = layout.get_pixel_size()
|
2012-05-30 12:01:10 +00:00
|
|
|
x = (w/2)-(textw/2) + x
|
|
|
|
y = (h/2) - (texth/2) + y
|
2012-04-12 19:43:12 +00:00
|
|
|
ctx.move_to(x, y)
|
2012-04-12 19:45:29 +00:00
|
|
|
self.window.draw_layout(self.style.light_gc[gtk.STATE_NORMAL], int(x), int(y), layout)
|
2012-04-12 19:43:12 +00:00
|
|
|
|
|
|
|
def set_count(self, count):
|
|
|
|
self.count = count
|
|
|
|
|
|
|
|
def set_active(self, active):
|
|
|
|
if active:
|
|
|
|
self.color = HobColors.DEEP_RED
|
2012-03-20 10:06:13 +00:00
|
|
|
else:
|
2012-04-12 19:43:12 +00:00
|
|
|
self.color = HobColors.GRAY
|
|
|
|
|
|
|
|
class HobTabLabel(gtk.HBox):
|
|
|
|
def __init__(self, text, count=0):
|
|
|
|
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)
|
2012-04-09 14:13:34 +00:00
|
|
|
|
2012-04-12 19:43:12 +00:00
|
|
|
def set_count(self, count):
|
|
|
|
self.indicator.set_count(count)
|
Hob: implement a self-defined notebook visual component for Hob
In recipe selection page, package selection page, and build details page, etc, there is a notebook component which is not gtk.Notebook in the design video.
We implement the visual component with a drawing area, and use it to replace the old notebook in recipe selection page and package selection page. The reasons why we do it are:
1) General speaking, gtk.Notebook doesn't look like the designer worked out. (see https://wiki.yoctoproject.org/wiki/File:Hob1.2-screencast2.mov)
2) And the designer version looks better, for example, there is an indicator to show how many recipes or packages are included, and how many issues happened when building? Very straightforward.
But technically, gtk.Notebook can't implement that, as far as we know.
3) Moreover, there is an entry for "search recipes", and "search packages". How to make it horizontal to the tabs is a problem to us.
Regarding those, we give up gtk.Notebook and use our own.
(From Poky rev: e4ebac226cc5e4589bcecd8bada9fde462e925cc)
(Bitbake rev: b0c2ca3f600694c6d37924006de3f9474b2a9a8e)
Signed-off-by: Liming An <limingx.l.an@intel.com>
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-27 05:28:26 +00:00
|
|
|
|
2012-04-12 19:43:12 +00:00
|
|
|
def set_active(self, active=True):
|
|
|
|
self.indicator.set_active(active)
|
Hob: implement a self-defined notebook visual component for Hob
In recipe selection page, package selection page, and build details page, etc, there is a notebook component which is not gtk.Notebook in the design video.
We implement the visual component with a drawing area, and use it to replace the old notebook in recipe selection page and package selection page. The reasons why we do it are:
1) General speaking, gtk.Notebook doesn't look like the designer worked out. (see https://wiki.yoctoproject.org/wiki/File:Hob1.2-screencast2.mov)
2) And the designer version looks better, for example, there is an indicator to show how many recipes or packages are included, and how many issues happened when building? Very straightforward.
But technically, gtk.Notebook can't implement that, as far as we know.
3) Moreover, there is an entry for "search recipes", and "search packages". How to make it horizontal to the tabs is a problem to us.
Regarding those, we give up gtk.Notebook and use our own.
(From Poky rev: e4ebac226cc5e4589bcecd8bada9fde462e925cc)
(Bitbake rev: b0c2ca3f600694c6d37924006de3f9474b2a9a8e)
Signed-off-by: Liming An <limingx.l.an@intel.com>
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-27 05:28:26 +00:00
|
|
|
|
2012-04-12 19:43:12 +00:00
|
|
|
class HobNotebook(gtk.Notebook):
|
|
|
|
def __init__(self):
|
|
|
|
gtk.Notebook.__init__(self)
|
|
|
|
self.set_property('homogeneous', True)
|
Hob: implement a self-defined notebook visual component for Hob
In recipe selection page, package selection page, and build details page, etc, there is a notebook component which is not gtk.Notebook in the design video.
We implement the visual component with a drawing area, and use it to replace the old notebook in recipe selection page and package selection page. The reasons why we do it are:
1) General speaking, gtk.Notebook doesn't look like the designer worked out. (see https://wiki.yoctoproject.org/wiki/File:Hob1.2-screencast2.mov)
2) And the designer version looks better, for example, there is an indicator to show how many recipes or packages are included, and how many issues happened when building? Very straightforward.
But technically, gtk.Notebook can't implement that, as far as we know.
3) Moreover, there is an entry for "search recipes", and "search packages". How to make it horizontal to the tabs is a problem to us.
Regarding those, we give up gtk.Notebook and use our own.
(From Poky rev: e4ebac226cc5e4589bcecd8bada9fde462e925cc)
(Bitbake rev: b0c2ca3f600694c6d37924006de3f9474b2a9a8e)
Signed-off-by: Liming An <limingx.l.an@intel.com>
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-27 05:28:26 +00:00
|
|
|
|
2012-04-12 19:43:12 +00:00
|
|
|
self.pages = []
|
Hob: implement a self-defined notebook visual component for Hob
In recipe selection page, package selection page, and build details page, etc, there is a notebook component which is not gtk.Notebook in the design video.
We implement the visual component with a drawing area, and use it to replace the old notebook in recipe selection page and package selection page. The reasons why we do it are:
1) General speaking, gtk.Notebook doesn't look like the designer worked out. (see https://wiki.yoctoproject.org/wiki/File:Hob1.2-screencast2.mov)
2) And the designer version looks better, for example, there is an indicator to show how many recipes or packages are included, and how many issues happened when building? Very straightforward.
But technically, gtk.Notebook can't implement that, as far as we know.
3) Moreover, there is an entry for "search recipes", and "search packages". How to make it horizontal to the tabs is a problem to us.
Regarding those, we give up gtk.Notebook and use our own.
(From Poky rev: e4ebac226cc5e4589bcecd8bada9fde462e925cc)
(Bitbake rev: b0c2ca3f600694c6d37924006de3f9474b2a9a8e)
Signed-off-by: Liming An <limingx.l.an@intel.com>
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-27 05:28:26 +00:00
|
|
|
|
|
|
|
self.search = None
|
|
|
|
self.search_name = ""
|
|
|
|
|
2012-04-12 19:43:12 +00:00
|
|
|
self.connect("switch-page", self.page_changed_cb)
|
Hob: implement a self-defined notebook visual component for Hob
In recipe selection page, package selection page, and build details page, etc, there is a notebook component which is not gtk.Notebook in the design video.
We implement the visual component with a drawing area, and use it to replace the old notebook in recipe selection page and package selection page. The reasons why we do it are:
1) General speaking, gtk.Notebook doesn't look like the designer worked out. (see https://wiki.yoctoproject.org/wiki/File:Hob1.2-screencast2.mov)
2) And the designer version looks better, for example, there is an indicator to show how many recipes or packages are included, and how many issues happened when building? Very straightforward.
But technically, gtk.Notebook can't implement that, as far as we know.
3) Moreover, there is an entry for "search recipes", and "search packages". How to make it horizontal to the tabs is a problem to us.
Regarding those, we give up gtk.Notebook and use our own.
(From Poky rev: e4ebac226cc5e4589bcecd8bada9fde462e925cc)
(Bitbake rev: b0c2ca3f600694c6d37924006de3f9474b2a9a8e)
Signed-off-by: Liming An <limingx.l.an@intel.com>
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-27 05:28:26 +00:00
|
|
|
|
|
|
|
self.show_all()
|
|
|
|
|
2012-04-12 19:43:12 +00:00
|
|
|
def page_changed_cb(self, nb, page, page_num):
|
|
|
|
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)
|
Hob: implement a self-defined notebook visual component for Hob
In recipe selection page, package selection page, and build details page, etc, there is a notebook component which is not gtk.Notebook in the design video.
We implement the visual component with a drawing area, and use it to replace the old notebook in recipe selection page and package selection page. The reasons why we do it are:
1) General speaking, gtk.Notebook doesn't look like the designer worked out. (see https://wiki.yoctoproject.org/wiki/File:Hob1.2-screencast2.mov)
2) And the designer version looks better, for example, there is an indicator to show how many recipes or packages are included, and how many issues happened when building? Very straightforward.
But technically, gtk.Notebook can't implement that, as far as we know.
3) Moreover, there is an entry for "search recipes", and "search packages". How to make it horizontal to the tabs is a problem to us.
Regarding those, we give up gtk.Notebook and use our own.
(From Poky rev: e4ebac226cc5e4589bcecd8bada9fde462e925cc)
(Bitbake rev: b0c2ca3f600694c6d37924006de3f9474b2a9a8e)
Signed-off-by: Liming An <limingx.l.an@intel.com>
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-27 05:28:26 +00:00
|
|
|
|
|
|
|
def set_entry(self, name="Search:"):
|
|
|
|
self.search = gtk.Entry()
|
|
|
|
self.search_name = name
|
|
|
|
style = self.search.get_style()
|
|
|
|
style.text[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(HobColors.GRAY, False, False)
|
|
|
|
self.search.set_style(style)
|
|
|
|
self.search.set_text(name)
|
|
|
|
self.search.set_editable(False)
|
2012-03-20 16:50:15 +00:00
|
|
|
self.search.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY, gtk.STOCK_CLEAR)
|
|
|
|
self.search.connect("icon-release", self.set_search_entry_clear_cb)
|
Hob: implement a self-defined notebook visual component for Hob
In recipe selection page, package selection page, and build details page, etc, there is a notebook component which is not gtk.Notebook in the design video.
We implement the visual component with a drawing area, and use it to replace the old notebook in recipe selection page and package selection page. The reasons why we do it are:
1) General speaking, gtk.Notebook doesn't look like the designer worked out. (see https://wiki.yoctoproject.org/wiki/File:Hob1.2-screencast2.mov)
2) And the designer version looks better, for example, there is an indicator to show how many recipes or packages are included, and how many issues happened when building? Very straightforward.
But technically, gtk.Notebook can't implement that, as far as we know.
3) Moreover, there is an entry for "search recipes", and "search packages". How to make it horizontal to the tabs is a problem to us.
Regarding those, we give up gtk.Notebook and use our own.
(From Poky rev: e4ebac226cc5e4589bcecd8bada9fde462e925cc)
(Bitbake rev: b0c2ca3f600694c6d37924006de3f9474b2a9a8e)
Signed-off-by: Liming An <limingx.l.an@intel.com>
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-27 05:28:26 +00:00
|
|
|
self.search.show()
|
|
|
|
|
|
|
|
self.search.connect("focus-in-event", self.set_search_entry_editable_cb)
|
|
|
|
self.search.connect("focus-out-event", self.set_search_entry_reset_cb)
|
2012-04-12 19:43:12 +00:00
|
|
|
self.set_action_widget(self.search, gtk.PACK_END)
|
Hob: implement a self-defined notebook visual component for Hob
In recipe selection page, package selection page, and build details page, etc, there is a notebook component which is not gtk.Notebook in the design video.
We implement the visual component with a drawing area, and use it to replace the old notebook in recipe selection page and package selection page. The reasons why we do it are:
1) General speaking, gtk.Notebook doesn't look like the designer worked out. (see https://wiki.yoctoproject.org/wiki/File:Hob1.2-screencast2.mov)
2) And the designer version looks better, for example, there is an indicator to show how many recipes or packages are included, and how many issues happened when building? Very straightforward.
But technically, gtk.Notebook can't implement that, as far as we know.
3) Moreover, there is an entry for "search recipes", and "search packages". How to make it horizontal to the tabs is a problem to us.
Regarding those, we give up gtk.Notebook and use our own.
(From Poky rev: e4ebac226cc5e4589bcecd8bada9fde462e925cc)
(Bitbake rev: b0c2ca3f600694c6d37924006de3f9474b2a9a8e)
Signed-off-by: Liming An <limingx.l.an@intel.com>
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2012-02-27 05:28:26 +00:00
|
|
|
|
2012-03-12 12:55:44 +00:00
|
|
|
def show_indicator_icon(self, title, number):
|
2012-04-12 19:43:12 +00:00
|
|
|
for child in self.pages:
|
|
|
|
if child.lbl.get_label() == title:
|
|
|
|
child.set_count(number)
|
2012-03-12 12:55:44 +00:00
|
|
|
|
|
|
|
def hide_indicator_icon(self, title):
|
2012-04-12 19:43:12 +00:00
|
|
|
for child in self.pages:
|
|
|
|
if child.lbl.get_label() == title:
|
|
|
|
child.set_count(0)
|
2012-03-16 14:28:13 +00:00
|
|
|
|
|
|
|
def set_search_entry_editable_cb(self, search, event):
|
|
|
|
search.set_editable(True)
|
|
|
|
search.set_text("")
|
|
|
|
style = self.search.get_style()
|
|
|
|
style.text[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(HobColors.BLACK, False, False)
|
|
|
|
search.set_style(style)
|
|
|
|
|
2012-03-20 16:50:15 +00:00
|
|
|
def reset_entry(self, entry):
|
|
|
|
style = entry.get_style()
|
2012-03-16 14:28:13 +00:00
|
|
|
style.text[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(HobColors.GRAY, False, False)
|
2012-03-20 16:50:15 +00:00
|
|
|
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):
|
2012-06-01 10:40:58 +00:00
|
|
|
if search.get_editable() == True:
|
|
|
|
search.set_text("")
|
2012-05-21 14:41:21 +00:00
|
|
|
|
2012-06-14 12:22:25 +00:00
|
|
|
def set_page(self, title):
|
|
|
|
for child in self.pages:
|
|
|
|
if child.lbl.get_label() == title:
|
|
|
|
child.grab_focus()
|
2012-11-20 12:37:46 +00:00
|
|
|
self.set_current_page(self.pages.index(child))
|
|
|
|
return
|
2012-06-14 12:22:25 +00:00
|
|
|
|
2012-03-22 11:03:35 +00:00
|
|
|
class HobWarpCellRendererText(gtk.CellRendererText):
|
|
|
|
def __init__(self, col_number):
|
|
|
|
gtk.CellRendererText.__init__(self)
|
|
|
|
self.set_property("wrap-mode", pango.WRAP_WORD_CHAR)
|
|
|
|
self.set_property("wrap-width", 300) # default value wrap width is 300
|
|
|
|
self.col_n = col_number
|
|
|
|
|
|
|
|
def do_render(self, window, widget, background_area, cell_area, expose_area, flags):
|
|
|
|
if widget:
|
|
|
|
self.props.wrap_width = self.get_resized_wrap_width(widget, widget.get_column(self.col_n))
|
|
|
|
return gtk.CellRendererText.do_render(self, window, widget, background_area, cell_area, expose_area, flags)
|
|
|
|
|
|
|
|
def get_resized_wrap_width(self, treeview, column):
|
|
|
|
otherCols = []
|
|
|
|
for col in treeview.get_columns():
|
|
|
|
if col != column:
|
|
|
|
otherCols.append(col)
|
|
|
|
adjwidth = treeview.allocation.width - sum(c.get_width() for c in otherCols)
|
|
|
|
adjwidth -= treeview.style_get_property("horizontal-separator") * 4
|
|
|
|
if self.props.wrap_width == adjwidth or adjwidth <= 0:
|
|
|
|
adjwidth = self.props.wrap_width
|
|
|
|
return adjwidth
|
|
|
|
|
|
|
|
gobject.type_register(HobWarpCellRendererText)
|
2012-03-23 14:29:46 +00:00
|
|
|
|
2012-03-23 15:32:17 +00:00
|
|
|
class HobIconChecker(hic):
|
|
|
|
def set_hob_icon_to_stock_icon(self, file_path, stock_id=""):
|
|
|
|
try:
|
|
|
|
pixbuf = gtk.gdk.pixbuf_new_from_file(file_path)
|
|
|
|
except Exception, e:
|
|
|
|
return None
|
|
|
|
|
|
|
|
if stock_id and (gtk.icon_factory_lookup_default(stock_id) == None):
|
|
|
|
icon_factory = gtk.IconFactory()
|
|
|
|
icon_factory.add_default()
|
|
|
|
icon_factory.add(stock_id, gtk.IconSet(pixbuf))
|
|
|
|
gtk.stock_add([(stock_id, '_label', 0, 0, '')])
|
|
|
|
|
|
|
|
return icon_factory.lookup(stock_id)
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
"""
|
|
|
|
For make hob icon consistently by request, and avoid icon view diff by system or gtk version, we use some 'hob icon' to replace the 'gtk icon'.
|
|
|
|
this function check the stock_id and make hob_id to replaced the gtk_id then return it or ""
|
|
|
|
"""
|
|
|
|
def check_stock_icon(self, stock_name=""):
|
|
|
|
HOB_CHECK_STOCK_NAME = {
|
2012-04-02 15:22:37 +00:00
|
|
|
('hic-dialog-info', 'gtk-dialog-info', 'dialog-info') : self.ICON_INDI_INFO_FILE,
|
2012-03-23 15:32:17 +00:00
|
|
|
('hic-ok', 'gtk-ok', 'ok') : self.ICON_INDI_TICK_FILE,
|
|
|
|
('hic-dialog-error', 'gtk-dialog-error', 'dialog-error') : self.ICON_INDI_ERROR_FILE,
|
|
|
|
('hic-dialog-warning', 'gtk-dialog-warning', 'dialog-warning') : self.ICON_INDI_ALERT_FILE,
|
2012-03-27 15:15:45 +00:00
|
|
|
('hic-task-refresh', 'gtk-execute', 'execute') : self.ICON_INDI_REFRESH_FILE,
|
2012-03-23 15:32:17 +00:00
|
|
|
}
|
|
|
|
valid_stock_id = stock_name
|
|
|
|
if stock_name:
|
|
|
|
for names, path in HOB_CHECK_STOCK_NAME.iteritems():
|
|
|
|
if stock_name in names:
|
|
|
|
valid_stock_id = names[0]
|
|
|
|
if not gtk.icon_factory_lookup_default(valid_stock_id):
|
|
|
|
self.set_hob_icon_to_stock_icon(path, valid_stock_id)
|
|
|
|
|
|
|
|
return valid_stock_id
|
|
|
|
|
2012-04-09 14:13:32 +00:00
|
|
|
class HobCellRendererController(gobject.GObject):
|
|
|
|
(MODE_CYCLE_RUNNING, MODE_ONE_SHORT) = range(2)
|
|
|
|
__gsignals__ = {
|
|
|
|
"run-timer-stopped" : (gobject.SIGNAL_RUN_LAST,
|
|
|
|
gobject.TYPE_NONE,
|
|
|
|
()),
|
|
|
|
}
|
|
|
|
def __init__(self, runningmode=MODE_CYCLE_RUNNING, is_draw_row=False):
|
2012-03-23 14:29:46 +00:00
|
|
|
gobject.GObject.__init__(self)
|
|
|
|
self.timeout_id = None
|
|
|
|
self.current_angle_pos = 0.0
|
|
|
|
self.step_angle = 0.0
|
|
|
|
self.tree_headers_height = 0
|
|
|
|
self.running_cell_areas = []
|
2012-04-09 14:13:32 +00:00
|
|
|
self.running_mode = runningmode
|
|
|
|
self.is_queue_draw_row_area = is_draw_row
|
|
|
|
self.force_stop_enable = False
|
2012-03-23 14:29:46 +00:00
|
|
|
|
|
|
|
def is_active(self):
|
|
|
|
if self.timeout_id:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
2012-04-09 14:13:32 +00:00
|
|
|
def reset_run(self):
|
|
|
|
self.force_stop()
|
|
|
|
self.running_cell_areas = []
|
2012-03-23 14:29:46 +00:00
|
|
|
self.current_angle_pos = 0.0
|
|
|
|
self.step_angle = 0.0
|
|
|
|
|
|
|
|
''' time_iterval: (1~1000)ms, which will be as the basic interval count for timer
|
|
|
|
init_usrdata: the current data which related the progress-bar will be at
|
|
|
|
min_usrdata: the range of min of user data
|
|
|
|
max_usrdata: the range of max of user data
|
|
|
|
step: each step which you want to progress
|
|
|
|
Note: the init_usrdata should in the range of from min to max, and max should > min
|
|
|
|
step should < (max - min)
|
|
|
|
'''
|
|
|
|
def start_run(self, time_iterval, init_usrdata, min_usrdata, max_usrdata, step, tree):
|
|
|
|
if (not time_iterval) or (not max_usrdata):
|
|
|
|
return
|
|
|
|
usr_range = (max_usrdata - min_usrdata) * 1.0
|
|
|
|
self.current_angle_pos = (init_usrdata * 1.0) / usr_range
|
|
|
|
self.step_angle = (step * 1) / usr_range
|
|
|
|
self.timeout_id = gobject.timeout_add(int(time_iterval),
|
|
|
|
self.make_image_on_progressing_cb, tree)
|
|
|
|
self.tree_headers_height = self.get_treeview_headers_height(tree)
|
2012-04-09 14:13:32 +00:00
|
|
|
self.force_stop_enable = False
|
2012-03-23 14:29:46 +00:00
|
|
|
|
2012-04-09 14:13:32 +00:00
|
|
|
def force_stop(self):
|
|
|
|
self.emit("run-timer-stopped")
|
|
|
|
self.force_stop_enable = True
|
2012-03-23 14:29:46 +00:00
|
|
|
if self.timeout_id:
|
2012-04-09 14:13:32 +00:00
|
|
|
if gobject.source_remove(self.timeout_id):
|
|
|
|
self.timeout_id = None
|
2012-03-23 14:29:46 +00:00
|
|
|
|
2012-04-09 14:13:32 +00:00
|
|
|
def on_draw_pixbuf_cb(self, pixbuf, cr, x, y, img_width, img_height, do_refresh=True):
|
2012-03-23 14:29:46 +00:00
|
|
|
if pixbuf:
|
|
|
|
r = max(img_width/2, img_height/2)
|
|
|
|
cr.translate(x + r, y + r)
|
|
|
|
if do_refresh:
|
|
|
|
cr.rotate(2 * math.pi * self.current_angle_pos)
|
|
|
|
|
|
|
|
cr.set_source_pixbuf(pixbuf, -img_width/2, -img_height/2)
|
|
|
|
cr.paint()
|
|
|
|
|
2012-04-09 14:13:32 +00:00
|
|
|
def on_draw_fadeinout_cb(self, cr, color, x, y, width, height, do_fadeout=True):
|
|
|
|
if do_fadeout:
|
|
|
|
alpha = self.current_angle_pos * 0.8
|
|
|
|
else:
|
|
|
|
alpha = (1.0 - self.current_angle_pos) * 0.8
|
|
|
|
|
|
|
|
cr.set_source_rgba(color.red, color.green, color.blue, alpha)
|
|
|
|
cr.rectangle(x, y, width, height)
|
|
|
|
cr.fill()
|
|
|
|
|
2012-03-23 14:29:46 +00:00
|
|
|
def get_treeview_headers_height(self, tree):
|
|
|
|
if tree and (tree.get_property("headers-visible") == True):
|
|
|
|
height = tree.get_allocation().height - tree.get_bin_window().get_size()[1]
|
|
|
|
return height
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def make_image_on_progressing_cb(self, tree):
|
|
|
|
self.current_angle_pos += self.step_angle
|
2012-04-09 14:13:32 +00:00
|
|
|
if self.running_mode == self.MODE_CYCLE_RUNNING:
|
|
|
|
if (self.current_angle_pos >= 1):
|
|
|
|
self.current_angle_pos = self.step_angle
|
|
|
|
else:
|
|
|
|
if self.current_angle_pos > 1:
|
|
|
|
self.force_stop()
|
|
|
|
return False
|
|
|
|
|
|
|
|
if self.is_queue_draw_row_area:
|
|
|
|
for path in self.running_cell_areas:
|
|
|
|
rect = tree.get_cell_area(path, tree.get_column(0))
|
|
|
|
row_x, _, row_width, _ = tree.get_visible_rect()
|
|
|
|
tree.queue_draw_area(row_x, rect.y + self.tree_headers_height, row_width, rect.height)
|
|
|
|
else:
|
|
|
|
for rect in self.running_cell_areas:
|
|
|
|
tree.queue_draw_area(rect.x, rect.y + self.tree_headers_height, rect.width, rect.height)
|
2012-03-23 14:29:46 +00:00
|
|
|
|
2012-04-09 14:13:32 +00:00
|
|
|
return (not self.force_stop_enable)
|
2012-03-23 14:29:46 +00:00
|
|
|
|
|
|
|
def append_running_cell_area(self, cell_area):
|
|
|
|
if cell_area and (cell_area not in self.running_cell_areas):
|
|
|
|
self.running_cell_areas.append(cell_area)
|
|
|
|
|
|
|
|
def remove_running_cell_area(self, cell_area):
|
|
|
|
if cell_area in self.running_cell_areas:
|
|
|
|
self.running_cell_areas.remove(cell_area)
|
|
|
|
if not self.running_cell_areas:
|
2012-04-09 14:13:32 +00:00
|
|
|
self.reset_run()
|
2012-03-23 14:29:46 +00:00
|
|
|
|
2012-04-09 14:13:32 +00:00
|
|
|
gobject.type_register(HobCellRendererController)
|
2012-03-23 14:29:46 +00:00
|
|
|
|
|
|
|
class HobCellRendererPixbuf(gtk.CellRendererPixbuf):
|
|
|
|
def __init__(self):
|
|
|
|
gtk.CellRendererPixbuf.__init__(self)
|
2012-04-09 14:13:32 +00:00
|
|
|
self.control = HobCellRendererController()
|
2012-03-27 15:15:45 +00:00
|
|
|
# add icon checker for make the gtk-icon transfer to hob-icon
|
2012-03-23 15:32:17 +00:00
|
|
|
self.checker = HobIconChecker()
|
2012-03-29 12:54:56 +00:00
|
|
|
self.set_property("stock-size", gtk.ICON_SIZE_DND)
|
2012-03-23 14:29:46 +00:00
|
|
|
|
|
|
|
def get_pixbuf_from_stock_icon(self, widget, stock_id="", size=gtk.ICON_SIZE_DIALOG):
|
|
|
|
if widget and stock_id and gtk.icon_factory_lookup_default(stock_id):
|
|
|
|
return widget.render_icon(stock_id, size)
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
2012-03-23 15:32:17 +00:00
|
|
|
def set_icon_name_to_id(self, new_name):
|
|
|
|
if new_name and type(new_name) == str:
|
|
|
|
# check the name is need to transfer to hob icon or not
|
|
|
|
name = self.checker.check_stock_icon(new_name)
|
2012-03-27 15:15:45 +00:00
|
|
|
if name.startswith("hic") or name.startswith("gtk"):
|
2012-03-23 14:29:46 +00:00
|
|
|
stock_id = name
|
|
|
|
else:
|
|
|
|
stock_id = 'gtk-' + name
|
|
|
|
|
|
|
|
return stock_id
|
|
|
|
|
|
|
|
''' render cell exactly, "icon-name" is priority
|
2012-03-27 15:15:45 +00:00
|
|
|
if use the 'hic-task-refresh' will make the pix animation
|
2012-03-23 14:29:46 +00:00
|
|
|
if 'pix' will change the pixbuf for it from the pixbuf or image.
|
|
|
|
'''
|
|
|
|
def do_render(self, window, tree, background_area,cell_area, expose_area, flags):
|
|
|
|
if (not self.control) or (not tree):
|
|
|
|
return
|
|
|
|
|
|
|
|
x, y, w, h = self.on_get_size(tree, cell_area)
|
|
|
|
x += cell_area.x
|
|
|
|
y += cell_area.y
|
|
|
|
w -= 2 * self.get_property("xpad")
|
|
|
|
h -= 2 * self.get_property("ypad")
|
|
|
|
|
|
|
|
stock_id = ""
|
|
|
|
if self.props.icon_name:
|
|
|
|
stock_id = self.set_icon_name_to_id(self.props.icon_name)
|
|
|
|
elif self.props.stock_id:
|
|
|
|
stock_id = self.props.stock_id
|
|
|
|
elif self.props.pixbuf:
|
|
|
|
pix = self.props.pixbuf
|
|
|
|
else:
|
|
|
|
return
|
|
|
|
|
|
|
|
if stock_id:
|
|
|
|
pix = self.get_pixbuf_from_stock_icon(tree, stock_id, self.props.stock_size)
|
2012-03-27 15:15:45 +00:00
|
|
|
if stock_id == 'hic-task-refresh':
|
2012-03-23 14:29:46 +00:00
|
|
|
self.control.append_running_cell_area(cell_area)
|
|
|
|
if self.control.is_active():
|
2012-04-09 14:13:32 +00:00
|
|
|
self.control.on_draw_pixbuf_cb(pix, window.cairo_create(), x, y, w, h, True)
|
2012-03-23 14:29:46 +00:00
|
|
|
else:
|
2012-05-08 11:48:05 +00:00
|
|
|
self.control.start_run(200, 0, 0, 1000, 150, tree)
|
2012-03-23 14:29:46 +00:00
|
|
|
else:
|
|
|
|
self.control.remove_running_cell_area(cell_area)
|
2012-04-09 14:13:32 +00:00
|
|
|
self.control.on_draw_pixbuf_cb(pix, window.cairo_create(), x, y, w, h, False)
|
2012-03-23 14:29:46 +00:00
|
|
|
|
|
|
|
def on_get_size(self, widget, cell_area):
|
|
|
|
if self.props.icon_name or self.props.pixbuf or self.props.stock_id:
|
|
|
|
w, h = gtk.icon_size_lookup(self.props.stock_size)
|
2012-03-29 12:54:56 +00:00
|
|
|
calc_width = self.get_property("xpad") * 2 + w
|
|
|
|
calc_height = self.get_property("ypad") * 2 + h
|
|
|
|
x_offset = 0
|
|
|
|
y_offset = 0
|
|
|
|
if cell_area and w > 0 and h > 0:
|
|
|
|
x_offset = self.get_property("xalign") * (cell_area.width - calc_width - self.get_property("xpad"))
|
|
|
|
y_offset = self.get_property("yalign") * (cell_area.height - calc_height - self.get_property("ypad"))
|
|
|
|
|
|
|
|
return x_offset, y_offset, w, h
|
2012-03-23 14:29:46 +00:00
|
|
|
|
|
|
|
return 0, 0, 0, 0
|
|
|
|
|
|
|
|
gobject.type_register(HobCellRendererPixbuf)
|
2012-04-09 14:13:32 +00:00
|
|
|
|
|
|
|
class HobCellRendererToggle(gtk.CellRendererToggle):
|
|
|
|
def __init__(self):
|
|
|
|
gtk.CellRendererToggle.__init__(self)
|
|
|
|
self.ctrl = HobCellRendererController(is_draw_row=True)
|
|
|
|
self.ctrl.running_mode = self.ctrl.MODE_ONE_SHORT
|
2012-05-08 11:48:07 +00:00
|
|
|
self.cell_attr = {"fadeout": False, "number_of_children": 0}
|
2012-04-09 14:13:32 +00:00
|
|
|
|
|
|
|
def do_render(self, window, widget, background_area, cell_area, expose_area, flags):
|
|
|
|
if (not self.ctrl) or (not widget):
|
|
|
|
return
|
2012-05-08 11:48:07 +00:00
|
|
|
|
|
|
|
if flags & gtk.CELL_RENDERER_SELECTED:
|
|
|
|
state = gtk.STATE_SELECTED
|
|
|
|
else:
|
|
|
|
state = gtk.STATE_NORMAL
|
|
|
|
|
2012-04-09 14:13:32 +00:00
|
|
|
if self.ctrl.is_active():
|
2012-04-09 14:13:33 +00:00
|
|
|
path = widget.get_path_at_pos(cell_area.x + cell_area.width/2, cell_area.y + cell_area.height/2)
|
|
|
|
# sometimes the parameters of cell_area will be a negative number,such as pull up down the scroll bar
|
|
|
|
# it's over the tree container range, so the path will be bad
|
|
|
|
if not path: return
|
|
|
|
path = path[0]
|
2012-04-09 14:13:32 +00:00
|
|
|
if path in self.ctrl.running_cell_areas:
|
|
|
|
cr = window.cairo_create()
|
2012-05-08 11:48:07 +00:00
|
|
|
color = widget.get_style().base[state]
|
2012-04-09 14:13:32 +00:00
|
|
|
|
|
|
|
row_x, _, row_width, _ = widget.get_visible_rect()
|
|
|
|
border_y = self.get_property("ypad")
|
|
|
|
self.ctrl.on_draw_fadeinout_cb(cr, color, row_x, cell_area.y - border_y, row_width, \
|
|
|
|
cell_area.height + border_y * 2, self.cell_attr["fadeout"])
|
2012-05-08 11:48:07 +00:00
|
|
|
# draw number of a group
|
|
|
|
if self.cell_attr["number_of_children"]:
|
|
|
|
text = "%d pkg" % self.cell_attr["number_of_children"]
|
|
|
|
pangolayout = widget.create_pango_layout(text)
|
|
|
|
textw, texth = pangolayout.get_pixel_size()
|
|
|
|
x = cell_area.x + (cell_area.width/2) - (textw/2)
|
|
|
|
y = cell_area.y + (cell_area.height/2) - (texth/2)
|
|
|
|
|
|
|
|
widget.style.paint_layout(window, state, True, cell_area, widget, "checkbox", x, y, pangolayout)
|
|
|
|
else:
|
|
|
|
return gtk.CellRendererToggle.do_render(self, window, widget, background_area, cell_area, expose_area, flags)
|
2012-04-09 14:13:32 +00:00
|
|
|
|
|
|
|
'''delay: normally delay time is 1000ms
|
|
|
|
cell_list: whilch cells need to be render
|
|
|
|
'''
|
|
|
|
def fadeout(self, tree, delay, cell_list=None):
|
|
|
|
if (delay < 200) or (not tree):
|
|
|
|
return
|
|
|
|
self.cell_attr["fadeout"] = True
|
|
|
|
self.ctrl.running_cell_areas = cell_list
|
|
|
|
self.ctrl.start_run(200, 0, 0, delay, (delay * 200 / 1000), tree)
|
|
|
|
|
|
|
|
def connect_render_state_changed(self, func, usrdata=None):
|
|
|
|
if not func:
|
|
|
|
return
|
|
|
|
if usrdata:
|
|
|
|
self.ctrl.connect("run-timer-stopped", func, self, usrdata)
|
|
|
|
else:
|
|
|
|
self.ctrl.connect("run-timer-stopped", func, self)
|
|
|
|
|
|
|
|
gobject.type_register(HobCellRendererToggle)
|