def __init__(self, icon_theme=None): """ Creates an enhanced IconEntry that triggers a timeout when typing """ Gtk.Entry.__init__(self) self.set_size_request(em(9), em(1.7)) if not icon_theme: icon_theme = Gtk.IconTheme.get_default() self._handler_changed = self.connect_after("changed", self._on_changed) self.connect("icon-press", self._on_icon_pressed) self.set_icon_from_icon_name(Gtk.EntryIconPosition.PRIMARY, 'edit-find-symbolic') self.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, None) # set sensible atk name atk_desc = self.get_accessible() atk_desc.set_name(_("Search")) # data self._timeout_id = 0 self._undo_stack = [""] self._redo_stack = []
def __init__(self, icon_theme=None): """ Creates an enhanced IconEntry that triggers a timeout when typing """ Gtk.Entry.__init__(self) self.set_size_request(em(16), em(1.7)) if not icon_theme: icon_theme = Gtk.IconTheme.get_default() self._handler_changed = self.connect_after("changed", self._on_changed) self.connect("icon-press", self._on_icon_pressed) self.set_icon_from_icon_name(Gtk.EntryIconPosition.PRIMARY, 'edit-find-symbolic') self.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, None) # set sensible atk name atk_desc = self.get_accessible() atk_desc.set_name(_("Search")) # data self._timeout_id = 0 self._undo_stack = [""] self._redo_stack = []
def __init__(self): GObject.GObject.__init__(self) self.set_redraw_on_allocate(False) self.set_size_request(-1, em(1.75)) self._allocation = None # Accessibility info atk_desc = self.get_accessible() atk_desc.set_name(_("You are here:")) atk_desc.set_role(Atk.Role.PANEL) self.use_animations = True self.animator = PathBarAnimator(self) self.out_of_width = False self.psuedo_parts = [] # used for certain button press logic self._press_origin = None # tracks the id of the revealer timeout self._revealer = None # values derived from the gtk settings s = Gtk.Settings.get_default() # time to wait before revealing a part on enter event in ms self._timeout_reveal = s.get_property("gtk-tooltip-timeout") # time to wait until emitting click event in ms self._timeout_initial = s.get_property("gtk-timeout-initial") # les signales! self.connect('size-allocate', self._on_allocate) self.connect('draw', self._on_draw)
def __init__(self): GObject.GObject.__init__(self) self.set_redraw_on_allocate(False) self.set_size_request(-1, em(1.75)) self._allocation = None # Accessibility info atk_desc = self.get_accessible() atk_desc.set_name(_("You are here:")) atk_desc.set_role(Atk.Role.PANEL) self.use_animations = True self.animator = PathBarAnimator(self) self.out_of_width = False self.psuedo_parts = [] # used for certain button press logic self._press_origin = None # tracks the id of the revealer timeout self._revealer = None # values derived from the gtk settings s = Gtk.Settings.get_default() # time to wait before revealing a part on enter event in ms self._timeout_reveal = s.get_property("gtk-tooltip-timeout") # time to wait until emitting click event in ms self._timeout_initial = s.get_property("gtk-timeout-initial") # les signales! self.connect('size-allocate', self._on_allocate) self.connect('draw', self._on_draw) return
def _calc_row_heights(self, tr): ypad = StockEms.SMALL tr.set_property('xpad', StockEms.MEDIUM) tr.set_property('ypad', ypad) for btn in tr.get_buttons(): # recalc button geometry and cache btn.configure_geometry(self.create_pango_layout("")) btn_h = btn.height tr.normal_height = max(32 + 2 * ypad, em(2.5) + ypad) tr.selected_height = tr.normal_height + btn_h + StockEms.MEDIUM
def __init__(self, label, icon, icon_size=Gtk.IconSize.DIALOG): TileButton.__init__(self) self.set_size_request(em(8), -1) self.build_default(label, icon, icon_size) self.label.set_justify(Gtk.Justification.CENTER) self.label.set_alignment(0.5, 0.0) self.label.set_line_wrap(True) self.box.set_border_width(StockEms.SMALL) context = self.label.get_style_context() context.add_class("category-tile") self.connect("enter-notify-event", self.on_enter) self.connect("leave-notify-event", self.on_leave)
class _Tile(object): MIN_WIDTH = em(7) def __init__(self): self.set_focus_on_click(False) self.set_relief(Gtk.ReliefStyle.NONE) self.box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) self.box.set_size_request(self.MIN_WIDTH, -1) self.add(self.box) return def build_default(self, label, icon, icon_size): if icon is not None: self.image = _parse_icon(icon, icon_size) self.box.pack_start(self.image, True, True, 0) self.label = Gtk.Label.new(label) self.box.pack_start(self.label, True, True, 0) return
def __init__(self, app_view, db, icons, show_ratings, store=None): Gtk.TreeView.__init__(self) self._logger = logging.getLogger("softwarecenter.view.appview") self.app_view = app_view self.db = db self.pressed = False self.focal_btn = None self._action_block_list = [] self._needs_collapse = [] self.expanded_path = None self.selected_row_renderer = None # pixbuf for the icon that is displayed in the selected row self.selected_row_icon = None #~ # if this hacked mode is available everything will be fast #~ # and we can set fixed_height mode and still have growing rows #~ # (see upstream gnome #607447) try: self.set_property("ubuntu-almost-fixed-height-mode", True) self.set_fixed_height_mode(True) except: self._logger.warn( "ubuntu-almost-fixed-height-mode extension not available") self.set_headers_visible(False) # our custom renderer self._renderer = CellRendererAppView(icons, self.create_pango_layout(''), show_ratings, Icons.INSTALLED_OVERLAY) self._renderer.set_pixbuf_width(32) self._renderer.set_button_spacing(em(0.3)) # create buttons and set initial strings info = CellButtonRenderer(self, name=CellButtonIDs.INFO) info.set_markup_variants({self.VARIANT_INFO: _('More Info')}) action = CellButtonRenderer(self, name=CellButtonIDs.ACTION) action.set_markup_variants({ self.VARIANT_INSTALL: _('Install'), self.VARIANT_REMOVE: _('Remove'), self.VARIANT_PURCHASE: _(u'Buy\u2026') }) self._renderer.button_pack_start(info) self._renderer.button_pack_end(action) self._column = Gtk.TreeViewColumn( "Applications", self._renderer, application=AppGenericStore.COL_ROW_DATA) self._column.set_cell_data_func(self._renderer, self._cell_data_func_cb) self._column.set_fixed_width(200) self._column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) self.append_column(self._column) # network status watcher watcher = get_network_watcher() watcher.connect("changed", self._on_net_state_changed, self._renderer) # custom cursor self._cursor_hand = Gdk.Cursor.new(Gdk.CursorType.HAND2) self.connect("style-updated", self._on_style_updated, self._renderer) # button and motion are "special" self.connect("button-press-event", self._on_button_press_event, self._renderer) self.connect("button-release-event", self._on_button_release_event, self._renderer) self.connect("key-press-event", self._on_key_press_event, self._renderer) self.connect("key-release-event", self._on_key_release_event, self._renderer) self.connect("motion-notify-event", self._on_motion, self._renderer) self.connect("cursor-changed", self._on_cursor_changed, self._renderer) # our own "activate" handler self.connect("row-activated", self._on_row_activated, self._renderer) self.backend = get_install_backend() self._transactions_connected = False self.connect('realize', self._on_realize, self._renderer)
def __init__(self, app_view, db, icons, show_ratings, store=None): Gtk.TreeView.__init__(self) self._logger = logging.getLogger("softwarecenter.view.appview") self.app_view = app_view self.db = db self.pressed = False self.focal_btn = None self._action_block_list = [] self._needs_collapse = [] self.expanded_path = None #~ # if this hacked mode is available everything will be fast #~ # and we can set fixed_height mode and still have growing rows #~ # (see upstream gnome #607447) try: self.set_property("ubuntu-almost-fixed-height-mode", True) self.set_fixed_height_mode(True) except: self._logger.warn("ubuntu-almost-fixed-height-mode extension not available") self.set_headers_visible(False) # a11y: this is a cell renderer that only displays a icon, but still # has a markup property for orca and friends # we use it so that orca and other a11y tools get proper text to read # it needs to be the first one, because that is what the tools look # at by default tr = CellRendererAppView(icons, self.create_pango_layout(''), show_ratings, Icons.INSTALLED_OVERLAY) tr.set_pixbuf_width(32) tr.set_button_spacing(em(0.3)) # create buttons and set initial strings info = CellButtonRenderer(self, name=CellButtonIDs.INFO) info.set_markup_variants( {self.VARIANT_INFO: _('More Info')}) action = CellButtonRenderer(self, name=CellButtonIDs.ACTION) action.set_markup_variants( {self.VARIANT_INSTALL: _('Install'), self.VARIANT_REMOVE: _('Remove'), self.VARIANT_PURCHASE: _(u'Buy\u2026')}) tr.button_pack_start(info) tr.button_pack_end(action) column = Gtk.TreeViewColumn("Applications", tr, application=AppGenericStore.COL_ROW_DATA) column.set_cell_data_func(tr, self._cell_data_func_cb) column.set_fixed_width(200) column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) self.append_column(column) # network status watcher watcher = get_network_watcher() watcher.connect("changed", self._on_net_state_changed, tr) # custom cursor self._cursor_hand = Gdk.Cursor.new(Gdk.CursorType.HAND2) self.connect("style-updated", self._on_style_updated, tr) # button and motion are "special" self.connect("button-press-event", self._on_button_press_event, tr) self.connect("button-release-event", self._on_button_release_event, tr) self.connect("key-press-event", self._on_key_press_event, tr) self.connect("key-release-event", self._on_key_release_event, tr) self.connect("motion-notify-event", self._on_motion, tr) self.connect("cursor-changed", self._on_cursor_changed, tr) # our own "activate" handler self.connect("row-activated", self._on_row_activated, tr) self.backend = get_install_backend() self._transactions_connected = False self.connect('realize', self._on_realize, tr)
class PendingSymbolicIcon(SymbolicIcon, RotationAboutCenterAnimation): BUBBLE_MAX_BORDER_RADIUS = em() BUBBLE_XPADDING = 5 BUBBLE_YPADDING = 2 BUBBLE_FONT_DESC = "Bold 8.5" def __init__(self, name): SymbolicIcon.__init__(self, name) RotationAboutCenterAnimation.__init__(self) # for painting the trans count bubble self.layout = self.create_pango_layout("") self.transaction_count = 0 def on_draw(self, widget, cr, *args, **kwargs): cr.save() if self.is_animating(): # translate to the center, then set the rotation a = widget.get_allocation() cr.translate(a.width * 0.5, a.height * 0.5) cr.rotate(self.rotation) # pass on the translation details kwargs['xo'] = -(a.width * 0.5) kwargs['yo'] = -(a.height * 0.5) # do icon drawing SymbolicIcon.on_draw(self, widget, cr, *args, **kwargs) cr.restore() if not self.is_animating() or not self.transaction_count: return # paint transactions bubble # get the layout extents and calc the bubble size ex = self.layout.get_pixel_extents()[1] x = ((a.width - self.icon.get_width()) / 2 + self.icon.get_width() - ex.width + 2) y = ((a.height - self.icon.get_height()) / 2 + self.icon.get_height() - ex.height + 2) w = ex.width + 2 * self.BUBBLE_XPADDING h = ex.height + 2 * self.BUBBLE_YPADDING border_radius = w / 3 if border_radius > self.BUBBLE_MAX_BORDER_RADIUS: border_radius = self.BUBBLE_MAX_BORDER_RADIUS # paint background context = widget.get_style_context() context.save() color = context.get_background_color(Gtk.StateFlags.SELECTED) rounded_rect(cr, x + 1, y + 1, w - 2, h - 2, border_radius) Gdk.cairo_set_source_rgba(cr, color) cr.fill() context.restore() # paint outline rounded_rect(cr, x + 1.5, y + 1.5, w - 3, h - 3, border_radius - 1) cr.set_source_rgb(1, 1, 1) cr.set_line_width(1) cr.stroke() # paint layout cr.save() cr.translate(x + (w - ex.width) * 0.5, y + (h - ex.height) * 0.5) cr.move_to(0, 1) PangoCairo.layout_path(cr, self.layout) cr.set_source_rgba(0, 0, 0, 0.6) cr.fill() Gtk.render_layout(context, cr, 0, 0, self.layout) cr.restore() def set_transaction_count(self, count): if count == self.transaction_count: return self.transaction_count = count m = ('<span font_desc="%s" color="%s">%i</span>' % (self.BUBBLE_FONT_DESC, "white", count)) self.layout.set_markup(m, -1) self.queue_draw()
def __init__(self, helper, doc, icon_size=48): TileButton.__init__(self) self._pressed = False label = helper.get_appname(doc) icon = helper.get_icon_at_size(doc, icon_size, icon_size) stats = helper.get_review_stats(doc) doc.installed = doc.available = None self.is_installed = helper.is_installed(doc) self._overlay = helper.icons.load_icon(Icons.INSTALLED_OVERLAY, self.INSTALLED_OVERLAY_SIZE, 0) # flags self.box.set_orientation(Gtk.Orientation.HORIZONTAL) self.box.set_spacing(StockEms.SMALL) self.content_left = Gtk.Box.new(Gtk.Orientation.VERTICAL, StockEms.MEDIUM) self.content_right = Gtk.Box.new(Gtk.Orientation.VERTICAL, 1) self.box.pack_start(self.content_left, False, False, 0) self.box.pack_start(self.content_right, False, False, 0) self.image = _parse_icon(icon, icon_size) self.content_left.pack_start(self.image, False, False, 0) self.title = Gtk.Label.new(self._MARKUP % GObject.markup_escape_text(label)) self.title.set_alignment(0.0, 0.5) self.title.set_use_markup(True) self.title.set_ellipsize(Pango.EllipsizeMode.END) self.content_right.pack_start(self.title, False, False, 0) categories = helper.get_categories(doc) if categories is not None: self.category = Gtk.Label.new('<span font_desc="%i">%s</span>' % (em(0.6), GObject.markup_escape_text(categories))) self.category.set_use_markup(True) self.category.set_alignment(0.0, 0.5) self.category.set_ellipsize(Pango.EllipsizeMode.END) self.content_right.pack_start(self.category, False, False, 4) stats_a11y = None if stats is not None: self.stars = Star(size=StarSize.SMALL) self.stars.render_outline = True self.stars.set_rating(stats.ratings_average) self.rating_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, StockEms.SMALL) self.rating_box.pack_start(self.stars, False, False, 0) self.n_ratings = Gtk.Label.new( '<span font_desc="%i"> (%i)</span>' % ( em(0.45), stats.ratings_total)) self.n_ratings.set_use_markup(True) self.n_ratings.set_name("subtle-label") self.n_ratings.set_alignment(0.0, 0.5) self.rating_box.pack_start(self.n_ratings, False, False, 0) self.content_right.pack_start(self.rating_box, False, False, 0) # TRANSLATORS: this is an accessibility description for eg orca and # is not visible in the ui stats_a11y = _('%(stars)d stars - %(reviews)d reviews') % { 'stars': stats.ratings_average, 'reviews': stats.ratings_total} #work out width tile needs to be to ensure ratings text is all visible req_width = (self.stars.size_request().width + self.image.size_request().width + self.n_ratings.size_request().width + StockEms.MEDIUM * 3 ) global _global_featured_tile_width _global_featured_tile_width = max(_global_featured_tile_width, req_width) details = AppDetails(db=helper.db, doc=doc) price = details.price or _("Free") if price == '0.00': price = _("Free") if price != _("Free"): price = 'US$ ' + price self.price = Gtk.Label.new( '<span font_desc="%i">%s</span>' % (em(0.6), price)) self.price.set_use_markup(True) self.price.set_name("subtle-label") self.price.set_alignment(0.0, 0.5) self.content_right.pack_start(self.price, False, False, 0) self.set_name("featured-tile") a11y_name = '. '.join([t for t in [label, categories, stats_a11y, price] if t]) self.get_accessible().set_name(a11y_name) backend = get_install_backend() backend.connect("transaction-finished", self.on_transaction_finished, helper, doc) self.connect("enter-notify-event", self.on_enter) self.connect("leave-notify-event", self.on_leave) self.connect("button-press-event", self.on_press) self.connect("button-release-event", self.on_release) return
cr.restore() return def on_enter(self, widget, event): window = self.get_window() window.set_cursor(_HAND) return def on_leave(self, widget, event): window = self.get_window() window.set_cursor(None) return _global_featured_tile_width = em(11) class FeaturedTile(TileButton): INSTALLED_OVERLAY_SIZE = 22 _MARKUP = '<b><small>%s</small></b>' def __init__(self, helper, doc, icon_size=48): TileButton.__init__(self) self._pressed = False label = helper.get_appname(doc) icon = helper.get_icon_at_size(doc, icon_size, icon_size) stats = helper.get_review_stats(doc) doc.installed = doc.available = None self.is_installed = helper.is_installed(doc) self._overlay = helper.icons.load_icon(Icons.INSTALLED_OVERLAY,
class SectionSelector(TileToggleButton): MIN_WIDTH = em(5) _MARKUP = '<small>%s</small>' def __init__(self, label, icon, icon_size=Gtk.IconSize.DIALOG): TileToggleButton.__init__(self) markup = self._MARKUP % label self.build_default(markup, icon, icon_size) self.label.set_use_markup(True) self.label.set_justify(Gtk.Justification.CENTER) context = self.get_style_context() context.add_class("section-sel-bg") context = self.label.get_style_context() context.add_class("section-sel") self.draw_hint_has_channel_selector = False self._alloc = None self._bg_cache = {} self.connect('size-allocate', self.on_size_allocate) self.connect('style-updated', self.on_style_updated) def on_size_allocate(self, *args): alloc = self.get_allocation() if (self._alloc is None or self._alloc.width != alloc.width or self._alloc.height != alloc.height): self._alloc = alloc # reset the bg cache self._bg_cache = {} def on_style_updated(self, *args): # also reset the bg cache self._bg_cache = {} def _cache_bg_for_state(self, state): a = self.get_allocation() # tmp surface on which we render the button bg as per the gtk # theme engine _surf = cairo.ImageSurface(cairo.FORMAT_ARGB32, a.width, a.height) cr = cairo.Context(_surf) context = self.get_style_context() context.save() context.set_state(state) Gtk.render_background(context, cr, -5, -5, a.width + 10, a.height + 10) Gtk.render_frame(context, cr, -5, -5, a.width + 10, a.height + 10) del cr # new surface which will be cached which surf = cairo.ImageSurface(cairo.FORMAT_ARGB32, a.width, a.height) cr = cairo.Context(surf) # gradient for masking lin = cairo.LinearGradient(0, 0, 0, a.height) lin.add_color_stop_rgba(0.0, 1, 1, 1, 0.1) lin.add_color_stop_rgba(0.25, 1, 1, 1, 0.7) lin.add_color_stop_rgba(0.5, 1, 1, 1, 1.0) lin.add_color_stop_rgba(0.75, 1, 1, 1, 0.7) lin.add_color_stop_rgba(1.0, 1, 1, 1, 0.1) cr.set_source_surface(_surf, 0, 0) cr.mask(lin) del cr # cache the resulting surf... self._bg_cache[state] = surf def do_draw(self, cr): state = self.get_state_flags() if self.get_active(): if state not in self._bg_cache: self._cache_bg_for_state(state) cr.set_source_surface(self._bg_cache[state], 0, 0) cr.paint() for child in self: self.propagate_draw(child, cr)
def __init__(self, helper, doc, icon_size=48): TileButton.__init__(self) self._pressed = False label = helper.get_appname(doc) icon = helper.get_icon_at_size(doc, icon_size, icon_size) stats = helper.get_review_stats(doc) helper.update_availability(doc) helper.connect("needs-refresh", self._on_needs_refresh, doc, icon_size) self.is_installed = helper.is_installed(doc) self._overlay = helper.icons.load_icon(Icons.INSTALLED_OVERLAY, self.INSTALLED_OVERLAY_SIZE, 0) # flags self.box.set_orientation(Gtk.Orientation.HORIZONTAL) self.box.set_spacing(StockEms.SMALL) self.content_left = Gtk.Box.new(Gtk.Orientation.VERTICAL, StockEms.MEDIUM) self.content_right = Gtk.Box.new(Gtk.Orientation.VERTICAL, 1) self.box.pack_start(self.content_left, False, False, 0) self.box.pack_start(self.content_right, False, False, 0) self.image = Gtk.Image() _update_icon(self.image, icon, icon_size) self.content_left.pack_start(self.image, False, False, 0) self.title = Gtk.Label.new(self._MARKUP % GObject.markup_escape_text(label)) self.title.set_alignment(0.0, 0.5) self.title.set_use_markup(True) self.title.set_tooltip_text(label) self.title.set_ellipsize(Pango.EllipsizeMode.END) self.content_right.pack_start(self.title, False, False, 0) categories = helper.get_categories(doc) if categories is not None: self.category = Gtk.Label.new( '<span font_desc="%i">%s</span>' % (em(0.6), GObject.markup_escape_text(categories))) self.category.set_use_markup(True) self.category.set_alignment(0.0, 0.5) self.category.set_ellipsize(Pango.EllipsizeMode.END) self.content_right.pack_start(self.category, False, False, 4) stats_a11y = None if stats is not None: self.stars = Star(size=StarSize.SMALL) self.stars.render_outline = True self.stars.set_rating(stats.ratings_average) self.rating_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, StockEms.SMALL) self.rating_box.pack_start(self.stars, False, False, 0) self.n_ratings = Gtk.Label.new( '<span font_desc="%i"> (%i)</span>' % (em(0.45), stats.ratings_total)) self.n_ratings.set_use_markup(True) self.n_ratings.set_name("subtle-label") self.n_ratings.set_alignment(0.0, 0.5) self.rating_box.pack_start(self.n_ratings, False, False, 0) self.content_right.pack_start(self.rating_box, False, False, 0) # TRANSLATORS: this is an accessibility description for eg orca and # is not visible in the ui stats_a11y = _('%(stars)d stars - %(reviews)d reviews') % { 'stars': stats.ratings_average, 'reviews': stats.ratings_total } # work out width tile needs to be to ensure ratings text is all # visible req_width = (self.stars.size_request().width + self.image.size_request().width + self.n_ratings.size_request().width + StockEms.MEDIUM * 3) global _global_featured_tile_width _global_featured_tile_width = max(_global_featured_tile_width, req_width) details = AppDetails(db=helper.db, doc=doc) # TRANSLATORS: Free here means Gratis price = details.price or _("Free") if price == '0.00': # TRANSLATORS: Free here means Gratis price = _("Free") # TRANSLATORS: Free here means Gratis if price != _("Free"): price = 'US$ ' + price self.price = Gtk.Label.new('<span font_desc="%i">%s</span>' % (em(0.6), price)) self.price.set_use_markup(True) self.price.set_name("subtle-label") self.price.set_alignment(0.0, 0.5) self.content_right.pack_start(self.price, False, False, 0) self.set_name("featured-tile") a11y_name = '. '.join( [t for t in [label, categories, stats_a11y, price] if t]) self.get_accessible().set_name(a11y_name) backend = get_install_backend() backend.connect("transaction-finished", self.on_transaction_finished, helper, doc) self.connect("enter-notify-event", self.on_enter) self.connect("leave-notify-event", self.on_leave) self.connect("button-press-event", self.on_press) self.connect("button-release-event", self.on_release)
for child in self: self.propagate_draw(child, cr) cr.restore() def on_enter(self, widget, event): window = self.get_window() window.set_cursor(_HAND) def on_leave(self, widget, event): window = self.get_window() window.set_cursor(None) _global_featured_tile_width = em(11) class FeaturedTile(TileButton): INSTALLED_OVERLAY_SIZE = 22 _MARKUP = '<b><small>%s</small></b>' def __init__(self, helper, doc, icon_size=48): TileButton.__init__(self) self._pressed = False label = helper.get_appname(doc) icon = helper.get_icon_at_size(doc, icon_size, icon_size) stats = helper.get_review_stats(doc) helper.update_availability(doc)