Ejemplo n.º 1
0
    def __init__(self, icons, layout, show_ratings, overlay_icon_name):
        GObject.GObject.__init__(self)

        # geometry-state values
        self.pixbuf_width = 0
        self.apptitle_width = 0
        self.apptitle_height = 0
        self.normal_height = 0
        self.selected_height = 0
        self.show_ratings = show_ratings

        # button packing
        self.button_spacing = 0
        self._buttons = {Gtk.PackType.START: [], Gtk.PackType.END: []}
        self._all_buttons = {}

        # cache a layout
        self._layout = layout
        # star painter, paints stars
        self._stars = StarRenderer()
        self._stars.size = StarSize.SMALL

        # icon/overlay jazz
        try:
            self._installed = icons.load_icon(overlay_icon_name,
                                              self.OVERLAY_SIZE, 0)
        except GObject.GError:
            # icon not present in theme, probably because running uninstalled
            self._installed = icons.load_icon('emblem-system',
                                              self.OVERLAY_SIZE, 0)
        return
Ejemplo n.º 2
0
    def __init__(self, icons, show_ratings, overlay_icon_name):
        GObject.GObject.__init__(self)

        # geometry-state values
        self.pixbuf_width = 0
        self.apptitle_width = 0
        self.apptitle_height = 0
        self.normal_height = 0
        self.selected_height = 0
        self.show_ratings = show_ratings

        # button packing
        self.button_spacing = 0
        self._buttons = {Gtk.PackType.START: [],
                         Gtk.PackType.END:   []}
        self._all_buttons = {}

        # cache a layout
        self._layout = None
        # star painter, paints stars
        self._stars = StarRenderer()
        self._stars.size = StarSize.SMALL

        # icon/overlay jazz
        try:
            self._installed = icons.load_icon(overlay_icon_name,
                                              self.OVERLAY_SIZE, 0)
        except GObject.GError:
            # icon not present in theme, probably because running uninstalled
            self._installed = icons.load_icon('emblem-system',
                                              self.OVERLAY_SIZE, 0)
        return
Ejemplo n.º 3
0
class CellRendererAppView(Gtk.CellRendererText):

    # x, y offsets for the overlay icon
    OVERLAY_XO = OVERLAY_YO = 2

    # size of the install overlay icon
    OVERLAY_SIZE = 16

    # ratings
    MAX_STARS = 5
    STAR_SIZE = EM

    # initialize declared properties (LP: #965937)
    application = GObject.Property(
        type=GObject.TYPE_PYOBJECT,
        nick='document',
        blurb='a xapian document containing pkg information',
        flags=(GObject.PARAM_READWRITE | GObject.PARAM_CONSTRUCT),
        default=None)
    isactive = GObject.Property(type=bool,
                                nick='isactive',
                                blurb='is cell active/selected',
                                flags=(GObject.PARAM_READWRITE
                                       | GObject.PARAM_CONSTRUCT),
                                default=False)

    def __init__(self, icons, layout, show_ratings, overlay_icon_name):
        Gtk.CellRendererText.__init__(self)

        # the icon pixbuf to be displayed in the row
        self.icon = None

        # geometry-state values
        self.pixbuf_width = 0
        self.apptitle_width = 0
        self.apptitle_height = 0
        self.normal_height = 0
        self.selected_height = 0
        self.show_ratings = show_ratings

        self.icon_x_offset = 0
        self.icon_y_offset = 0

        # button packing
        self.button_spacing = 0
        self._buttons = {Gtk.PackType.START: [], Gtk.PackType.END: []}
        self._all_buttons = {}

        # cache a layout
        self._layout = layout
        # star painter, paints stars
        self._stars = StarRenderer()
        self._stars.size = StarSize.SMALL

        # icon/overlay jazz
        try:
            self._installed = icons.load_icon(overlay_icon_name,
                                              self.OVERLAY_SIZE, 0)
        except GObject.GError:
            # icon not present in theme, probably because running uninstalled
            self._installed = icons.load_icon('emblem-system',
                                              self.OVERLAY_SIZE, 0)

    def _layout_get_pixel_width(self, layout):
        return layout.get_size()[0] / Pango.SCALE

    def _layout_get_pixel_height(self, layout):
        return layout.get_size()[1] / Pango.SCALE

    def _render_category(self, context, cr, app, cell_area, layout, xpad, ypad,
                         is_rtl):

        layout.set_markup('<b>%s</b>' % app.display_name, -1)

        # work out max allowable layout width
        lw = self._layout_get_pixel_width(layout)
        lh = self._layout_get_pixel_height(layout)

        if not is_rtl:
            x = cell_area.x
        else:
            x = cell_area.x + cell_area.width - lw
        y = cell_area.y + (cell_area.height - lh) / 2

        Gtk.render_layout(context, cr, x, y, layout)

    def _render_price(self, context, cr, app, layout, cell_area, xpad, ypad,
                      is_rtl):
        layout.set_markup("%s" % self.model.get_display_price(app))

        if is_rtl:
            x = cell_area.x + xpad
        else:
            x = (cell_area.x + cell_area.width - xpad -
                 self._layout_get_pixel_width(layout))

        Gtk.render_layout(context, cr, x, ypad + cell_area.y, layout)

    def _render_icon(self, cr, app, cell_area, xpad, ypad, is_rtl):
        # calc offsets so icon is nicely centered
        self.icon = self.model.get_icon(app)
        self.icon_x_offset = xpad + cell_area.x
        self.icon_y_offset = ypad + cell_area.y
        xo = (self.pixbuf_width - self.icon.get_width()) / 2

        if not is_rtl:
            x = cell_area.x + xo + xpad
        else:
            x = cell_area.x + cell_area.width + xo - self.pixbuf_width - xpad
        y = cell_area.y + ypad

        # draw appicon pixbuf
        Gdk.cairo_set_source_pixbuf(cr, self.icon, x, y)
        cr.paint()

        # draw overlay if application is installed
        if self.model.is_installed(app):
            if not is_rtl:
                x += (self.pixbuf_width - self.OVERLAY_SIZE + self.OVERLAY_XO)
            else:
                x -= self.OVERLAY_XO
            y += (self.pixbuf_width - self.OVERLAY_SIZE + self.OVERLAY_YO)
            Gdk.cairo_set_source_pixbuf(cr, self._installed, x, y)
            cr.paint()

    def _render_summary(self, context, cr, app, cell_area, layout, xpad, ypad,
                        star_width, is_rtl):

        layout.set_markup(self.model.get_markup(app), -1)

        # work out max allowable layout width
        layout.set_width(-1)
        lw = self._layout_get_pixel_width(layout)
        max_layout_width = (cell_area.width - self.pixbuf_width - 3 * xpad -
                            star_width)

        max_layout_width = cell_area.width - self.pixbuf_width - 3 * xpad

        stats = self.model.get_review_stats(app)
        if self.show_ratings and stats:
            max_layout_width -= star_width + 6 * xpad

        if (self.props.isactive
                and self.model.get_transaction_progress(app) > 0):
            action_btn = self.get_button_by_name(CellButtonIDs.ACTION)
            max_layout_width -= (xpad + action_btn.width)

        if lw >= max_layout_width:
            layout.set_width((max_layout_width) * Pango.SCALE)
            layout.set_ellipsize(Pango.EllipsizeMode.END)
            lw = max_layout_width

        apptitle_extents = layout.get_line_readonly(0).get_pixel_extents()[1]
        self.apptitle_width = apptitle_extents.width
        self.apptitle_height = apptitle_extents.height

        if not is_rtl:
            x = cell_area.x + 2 * xpad + self.pixbuf_width
        else:
            x = (cell_area.x + cell_area.width - lw - self.pixbuf_width -
                 2 * xpad)

        y = cell_area.y + ypad

        Gtk.render_layout(context, cr, x, y, layout)

    def _render_rating(self, context, cr, app, cell_area, layout, xpad, ypad,
                       star_width, star_height, is_rtl):

        stats = self.model.get_review_stats(app)
        if not stats:
            return

        sr = self._stars

        if not is_rtl:
            x = (cell_area.x + 3 * xpad + self.pixbuf_width +
                 self.apptitle_width)
        else:
            x = (cell_area.x + cell_area.width - 3 * xpad - self.pixbuf_width -
                 self.apptitle_width - star_width)

        y = cell_area.y + ypad + (self.apptitle_height - self.STAR_SIZE) / 2

        sr.rating = stats.ratings_average
        sr.render_star(context, cr, x, y)

        # and nr-reviews in parenthesis to the right of the title
        nreviews = stats.ratings_total
        s = "(%i)" % nreviews

        layout.set_markup("<small>%s</small>" % s, -1)

        if not is_rtl:
            x += xpad + star_width
        else:
            x -= xpad + self._layout_get_pixel_width(layout)

        context.save()
        context.add_class("cellrenderer-avgrating-label")
        Gtk.render_layout(context, cr, x, y, layout)
        context.restore()

    def _render_progress(self, context, cr, progress, cell_area, ypad, is_rtl):
        percent = progress * 0.01
        # per the spec, the progressbar should be the width of the action
        # button
        action_btn = self.get_button_by_name(CellButtonIDs.ACTION)

        x, _, w, h = action_btn.allocation
        # shift the bar to the top edge
        y = cell_area.y + ypad

        context.save()
        context.add_class("trough")

        Gtk.render_background(context, cr, x, y, w, h)
        Gtk.render_frame(context, cr, x, y, w, h)

        context.restore()

        bar_size = w * percent

        context.save()
        context.add_class("progressbar")

        if (bar_size > 0):
            if is_rtl:
                x += (w - bar_size)
            Gtk.render_activity(context, cr, x, y, bar_size, h)

        context.restore()

    def _render_buttons(self, context, cr, cell_area, layout, xpad, ypad,
                        is_rtl):

        # layout buttons and paint
        y = cell_area.y + cell_area.height - ypad
        spacing = self.button_spacing

        if not is_rtl:
            start = Gtk.PackType.START
            end = Gtk.PackType.END
            xs = cell_area.x + 2 * xpad + self.pixbuf_width
            xb = cell_area.x + cell_area.width - xpad
        else:
            start = Gtk.PackType.END
            end = Gtk.PackType.START
            xs = cell_area.x + xpad
            xb = cell_area.x + cell_area.width - 2 * xpad - self.pixbuf_width

        for btn in self._buttons[start]:
            btn.set_position(xs, y - btn.height)
            btn.render(context, cr, layout)
            xs += btn.width + spacing

        for btn in self._buttons[end]:
            xb -= btn.width
            btn.set_position(xb, y - btn.height)
            btn.render(context, cr, layout)

            xb -= spacing

    def set_pixbuf_width(self, w):
        self.pixbuf_width = w

    def set_button_spacing(self, spacing):
        self.button_spacing = spacing

    def get_button_by_name(self, name):
        if name in self._all_buttons:
            return self._all_buttons[name]

    def get_buttons(self):
        btns = ()
        for k, v in self._buttons.items():
            btns += tuple(v)
        return btns

    def button_pack(self, btn, pack_type=Gtk.PackType.START):
        self._buttons[pack_type].append(btn)
        self._all_buttons[btn.name] = btn

    def button_pack_start(self, btn):
        self.button_pack(btn, Gtk.PackType.START)

    def button_pack_end(self, btn):
        self.button_pack(btn, Gtk.PackType.END)

    def do_set_property(self, pspec, value):
        setattr(self, pspec.name, value)

    def do_get_property(self, pspec):
        return getattr(self, pspec.name)

    def do_get_preferred_height_for_width(self, treeview, width):

        if not self.get_properties("isactive")[0]:
            return self.normal_height, self.normal_height

        return self.selected_height, self.selected_height

    def do_render(self, cr, widget, bg_area, cell_area, flags):
        app = self.props.application
        if not app:
            return

        self.model = widget.appmodel

        context = widget.get_style_context()
        xpad = self.get_property('xpad')
        ypad = self.get_property('ypad')
        star_width, star_height = self._stars.get_visible_size(context)
        is_rtl = widget.get_direction() == Gtk.TextDirection.RTL
        layout = self._layout

        # important! ensures correct text rendering, esp. when using hicolor
        # theme
        #~ if (flags & Gtk.CellRendererState.SELECTED) != 0:
        #~ # this follows the behaviour that gtk+ uses for states in
        #~ # treeviews
        #~ if widget.has_focus():
        #~ state = Gtk.StateFlags.SELECTED
        #~ else:
        #~ state = Gtk.StateFlags.ACTIVE
        #~ else:
        #~ state = Gtk.StateFlags.NORMAL

        context.save()
        #~ context.set_state(state)

        if isinstance(app, CategoryRowReference):
            self._render_category(context, cr, app, cell_area, layout, xpad,
                                  ypad, is_rtl)
            return

        self._render_icon(cr, app, cell_area, xpad, ypad, is_rtl)

        self._render_summary(context, cr, app, cell_area, layout, xpad, ypad,
                             star_width, is_rtl)

        # only show ratings if we have one
        if self.show_ratings:
            self._render_rating(context, cr, app, cell_area, layout, xpad,
                                ypad, star_width, star_height, is_rtl)

        progress = self.model.get_transaction_progress(app)
        if progress > 0:
            self._render_progress(context, cr, progress, cell_area, ypad,
                                  is_rtl)

        elif self.model.is_purchasable(app):
            self._render_price(context, cr, app, layout, cell_area, xpad, ypad,
                               is_rtl)

        # below is the stuff that is only done for the active cell
        if not self.props.isactive:
            return

        self._render_buttons(context, cr, cell_area, layout, xpad, ypad,
                             is_rtl)

        context.restore()
Ejemplo n.º 4
0
class CellRendererAppView(Gtk.CellRendererText):

    # x, y offsets for the overlay icon
    OVERLAY_XO = OVERLAY_YO = 2

    # size of the install overlay icon
    OVERLAY_SIZE = 16
    
    # ratings
    MAX_STARS = 5
    STAR_SIZE = EM

    __gproperties__ = {
        'application' : (GObject.TYPE_PYOBJECT, 'document',
                         'a xapian document containing pkg information',
                         GObject.PARAM_READWRITE),

        'isactive'    : (bool, 'isactive', 'is cell active/selected', False,
                         GObject.PARAM_READWRITE),
                     }


    def __init__(self, icons, show_ratings, overlay_icon_name):
        GObject.GObject.__init__(self)

        # geometry-state values
        self.pixbuf_width = 0
        self.apptitle_width = 0
        self.apptitle_height = 0
        self.normal_height = 0
        self.selected_height = 0
        self.show_ratings = show_ratings

        # button packing
        self.button_spacing = 0
        self._buttons = {Gtk.PackType.START: [],
                         Gtk.PackType.END:   []}
        self._all_buttons = {}

        # cache a layout
        self._layout = None
        # star painter, paints stars
        self._stars = StarRenderer()
        self._stars.size = StarSize.SMALL

        # icon/overlay jazz
        try:
            self._installed = icons.load_icon(overlay_icon_name,
                                              self.OVERLAY_SIZE, 0)
        except GObject.GError:
            # icon not present in theme, probably because running uninstalled
            self._installed = icons.load_icon('emblem-system',
                                              self.OVERLAY_SIZE, 0)
        return

    def _layout_get_pixel_width(self, layout):
        return layout.get_size()[0] / Pango.SCALE

    def _layout_get_pixel_height(self, layout):
        return layout.get_size()[1] / Pango.SCALE

    def _render_category(self,
            context, cr, app, cell_area, layout, xpad, ypad, is_rtl):

        layout.set_markup('<b>%s</b>' % app.display_name, -1)

        # work out max allowable layout width
        lw = self._layout_get_pixel_width(layout)
        lh = self._layout_get_pixel_height(layout)

        if not is_rtl:
            x = cell_area.x
        else:
            x = cell_area.x + cell_area.width - lw
        y = cell_area.y + (cell_area.height - lh)/2
        #w = cell_area.width
        #h = cell_area.height

        Gtk.render_layout(context, cr, x, y, layout)
        return

    def _render_icon(self, cr, app, cell_area, xpad, ypad, is_rtl):
        # calc offsets so icon is nicely centered
        icon = self.model.get_icon(app)
        xo = (self.pixbuf_width - icon.get_width())/2

        if not is_rtl:
            x = cell_area.x + xo + xpad
        else:
            x = cell_area.x + cell_area.width + xo - self.pixbuf_width - xpad
        y = cell_area.y + ypad

        # draw appicon pixbuf
        Gdk.cairo_set_source_pixbuf(cr, icon, x, y)
        cr.paint()

        # draw overlay if application is installed
        if self.model.is_installed(app):
            if not is_rtl:
                x += (self.pixbuf_width - self.OVERLAY_SIZE + self.OVERLAY_XO)
            else:
                x -= self.OVERLAY_XO
            y += (self.pixbuf_width - self.OVERLAY_SIZE + self.OVERLAY_YO)
            Gdk.cairo_set_source_pixbuf(cr, self._installed, x, y)
            cr.paint()
        return

    def _render_summary(self, context, cr, app,
                        cell_area, layout, xpad, ypad,
                        star_width, is_rtl):

        layout.set_markup(self.model.get_markup(app), -1)

        # work out max allowable layout width
        layout.set_width(-1)
        lw = self._layout_get_pixel_width(layout)
        max_layout_width = (cell_area.width - self.pixbuf_width -
                            3*xpad - star_width)
                            
        max_layout_width = cell_area.width - self.pixbuf_width - 3*xpad
        
        stats = self.model.get_review_stats(app)
        if self.show_ratings and stats:
            max_layout_width -= star_width+6*xpad
            
        if self.props.isactive and self.model.get_transaction_progress(app) > 0:
            action_btn = self.get_button_by_name(CellButtonIDs.ACTION)
            max_layout_width -= (xpad + action_btn.width) 

        if lw >= max_layout_width:
            layout.set_width((max_layout_width)*Pango.SCALE)
            layout.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
            lw = max_layout_width

        apptitle_extents = layout.get_line_readonly(0).get_pixel_extents()[1]
        self.apptitle_width = apptitle_extents.width
        self.apptitle_height = apptitle_extents.height

        if not is_rtl:
            x = cell_area.x+2*xpad+self.pixbuf_width
        else:
            x = cell_area.x+cell_area.width-lw-self.pixbuf_width-2*xpad

        y = cell_area.y+ypad

        Gtk.render_layout(context, cr, x, y, layout)
        return

    def _render_rating(self, context, cr, app,
                       cell_area, layout, xpad, ypad,
                       star_width, star_height, is_rtl):

        stats = self.model.get_review_stats(app)
        if not stats: return
        sr = self._stars

        if not is_rtl:
            x = cell_area.x+3*xpad+self.pixbuf_width+self.apptitle_width
        else:
            x = (cell_area.x + cell_area.width
                 - 3*xpad
                 - self.pixbuf_width
                 - self.apptitle_width 
                 - star_width)

        y = cell_area.y + ypad + (self.apptitle_height-self.STAR_SIZE)/2

        sr.rating = stats.ratings_average
        sr.render_star(context, cr, x, y)
        
        # and nr-reviews in parenthesis to the right of the title
        nreviews = stats.ratings_total
        s = "(%i)" % nreviews

        layout.set_markup("<small>%s</small>" % s, -1)

        lw = self._layout_get_pixel_width(layout)
        w = star_width
        if not is_rtl:
            x += xpad+w
        else:
            x -= xpad+lw

        context.save()
        context.add_class("cellrenderer-avgrating-label")
        Gtk.render_layout(context, cr, x, y, layout)
        context.restore()
        return

    def _render_progress(self, context, cr, progress, cell_area, ypad, is_rtl):
        percent = progress * 0.01
        # per the spec, the progressbar should be the width of the action button
        action_btn = self.get_button_by_name(CellButtonIDs.ACTION)

        x, _, w, h = action_btn.allocation
        # shift the bar to the top edge
        y = cell_area.y + ypad

        context.save()
        context.add_class("trough")

        Gtk.render_background(context, cr, x, y, w, h)
        Gtk.render_frame(context, cr, x, y, w, h)

        context.restore ()

        bar_size = w * percent

        context.save ()
        context.add_class ("progressbar")

        if (bar_size > 0):
            if is_rtl:
                x += (w - bar_size)
            Gtk.render_activity(context, cr, x, y, bar_size, h)

        context.restore ()
        return

    def _render_buttons(self,
            context, cr, cell_area, layout, xpad, ypad,
            is_rtl, is_available):

        # layout buttons and paint
        y = cell_area.y+cell_area.height-ypad
        spacing = self.button_spacing

        if not is_rtl:
            start = Gtk.PackType.START
            end = Gtk.PackType.END
            xs = cell_area.x + 2*xpad + self.pixbuf_width
            xb = cell_area.x + cell_area.width - xpad
        else:
            start = Gtk.PackType.END
            end = Gtk.PackType.START
            xs = cell_area.x + xpad
            xb = cell_area.x + cell_area.width - 2*xpad - self.pixbuf_width

        for btn in self._buttons[start]:
            btn.set_position(xs, y-btn.height)
            btn.render(context, cr, layout)
            xs += btn.width + spacing

        for btn in self._buttons[end]:
            xb -= btn.width
            btn.set_position(xb, y-btn.height)
            #~ if not is_available:
                #~ btn.set_sensitive(False)
            btn.render(context, cr, layout)

            xb -= spacing
        return

    def set_pixbuf_width(self, w):
        self.pixbuf_width = w
        return

    def set_button_spacing(self, spacing):
        self.button_spacing = spacing
        return

    def get_button_by_name(self, name):
        if name in self._all_buttons:
            return self._all_buttons[name]
        return None

    def get_buttons(self):
        btns = ()
        for k, v in self._buttons.items():
            btns += tuple(v)
        return btns

    def button_pack(self, btn, pack_type=Gtk.PackType.START):
        self._buttons[pack_type].append(btn)
        self._all_buttons[btn.name] = btn
        return

    def button_pack_start(self, btn):
        self.button_pack(btn, Gtk.PackType.START)
        return

    def button_pack_end(self, btn):
        self.button_pack(btn, Gtk.PackType.END)
        return

    def do_set_property(self, pspec, value):
        setattr(self, pspec.name, value)

    def do_get_property(self, pspec):
        return getattr(self, pspec.name)

    def do_get_preferred_height_for_width(self, treeview, width):

        if not self.get_properties("isactive")[0]:
            return self.normal_height, self.normal_height

        return self.selected_height, self.selected_height

    def do_render(self, cr, widget, bg_area, cell_area, flags):
        app = self.props.application
        if not app: return

        self.model = widget.appmodel
        context = widget.get_style_context()
        xpad = self.get_property('xpad')
        ypad = self.get_property('ypad')
        star_width, star_height = self._stars.get_visible_size(context)
        is_rtl = widget.get_direction() == Gtk.TextDirection.RTL

        if not self._layout:
            self._layout = widget.create_pango_layout('')

        layout = self._layout

        # important! ensures correct text rendering, esp. when using hicolor theme
        #~ if (flags & Gtk.CellRendererState.SELECTED) != 0:
            #~ # this follows the behaviour that gtk+ uses for states in treeviews
            #~ if widget.has_focus():
                #~ state = Gtk.StateFlags.SELECTED
            #~ else:
                #~ state = Gtk.StateFlags.ACTIVE
        #~ else:
            #~ state = Gtk.StateFlags.NORMAL

        context.save()
        #~ context.set_state(state)

        if isinstance(app, CategoryRowReference):
            self._render_category(context, cr, app,
                                  cell_area,
                                  layout,
                                  xpad, ypad,
                                  is_rtl)
            return

        self._render_icon(cr, app,
                          cell_area,
                          xpad, ypad,
                          is_rtl)

        self._render_summary(context, cr, app,
                             cell_area,
                             layout,
                             xpad, ypad,
                             star_width,
                             is_rtl)
                             
        # only show ratings if we have one
        if self.show_ratings:
            self._render_rating(context, cr, app,
                                cell_area,
                                layout,
                                xpad, ypad,
                                star_width,
                                star_height,
                                is_rtl)

        progress = self.model.get_transaction_progress(app)
        #~ print progress
        if progress > 0:
            self._render_progress(context, cr, progress,
                                  cell_area,
                                  ypad,
                                  is_rtl)

        # below is the stuff that is only done for the active cell
        if not self.props.isactive:
            return

        is_available = self.model.is_available(app)
        self._render_buttons(context, cr,
                             cell_area,
                             layout,
                             xpad, ypad,
                             is_rtl,
                             is_available)

        context.restore()
        return