~jconti/recent-notifications/trunk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
"""
RoundedWidgets.py
April 22, 2011

Custom widgets that have rounded edges
"""

import logging
import math

from gi.repository import Gdk, GdkPixbuf, GObject, Gtk

from Theme import Color

logger = logging.getLogger("RoundedWidgets")

# Angles in pi/2 increments 
A0 = 0
A1 = math.pi / 2.0
A2 = math.pi
A3 = 3.0 * math.pi / 2.0
A4 = 2.0 * math.pi

def draw_rounded_box(cr, x, y, width, height, radius):
  """Draws a rounded box to a cairo context, but doesn't fill or stroke it
  so it can be used as a clipping region as well."""
  x1 = x
  y1 = y
  w = width
  h = height
  x2 = x1 + w
  y2 = y1 + h
  r = radius

  cr.move_to(x1 + r, y1)
  cr.line_to(x2 - r, y1)
  cr.arc(x2 - r, y1 + r, r, A3, A4)
  cr.line_to(x2, y2 - r)
  cr.arc(x2 - r, y2 - r, r, A0, A1)
  cr.line_to(x1 + r, y2)
  cr.arc(x1 + r, y2 - r, r, A1, A2)
  cr.line_to(x1, y1 + r)
  cr.arc(x1 + r, y1 + r, r, A2, A3)

class RoundedBox(Gtk.Box):
  """A simple container that draws a solid background with rounded edges"""
  BACKGROUND_COLOR = Color("#fff")
  def __init__(self, radius = 10):
    GObject.GObject.__init__(self)

    self._radius = radius

    self.set_double_buffered(False)
    self.set_redraw_on_allocate(True)

  def set_radius(self, radius):
    """Sets the radius of the curved edges of this box"""
    self._radius = radius
    self.queue_draw()

  def get_radius(self):
    """Gets the radius of the curved edges of this box"""
    return self._radius

  def do_expose_event(self, event):
    """Draws the background and propagates the event to the children"""
    window = self.get_window()
    alloc = self.get_allocation()
    cr = window.cairo_create()

    # Set the clipping region
    cr.rectangle(event.area.x, event.area.y, event.area.width,
        event.area.height)
    cr.clip()

    #TODO: Fix this hack
    color = RoundedBox.BACKGROUND_COLOR
    cr.set_source_rgb(color.red, color.green, color.blue)

    # Draw the rounded box
    draw_rounded_box(cr, alloc.x, alloc.y, alloc.width, alloc.height,
        self._radius)
    cr.fill()

    # Propagate the event to the children
    for child in self.get_children():
      self.propagate_expose(child, event)

class RoundedIcon(Gtk.Widget):
  """Draws a pixbuf with rounded edges"""
  def __init__(self, pixbuf = None, radius = 10):
    GObject.GObject.__init__(self)

    self._pixbuf = pixbuf
    self._radius = radius

    self.set_has_window(False)
    self.set_double_buffered(False)
    self.set_redraw_on_allocate(True)

  def set_from_pixbuf(self, pixbuf):
    """Sets the icon from a pixbuf"""
    self._pixbuf = pixbuf

  def do_expose_event(self, event):
    """Draws the pixbuf"""
    pixbuf = self._pixbuf
    if pixbuf == None:
      return

    window = self.get_window()
    alloc = self.get_allocation()
    cr = window.cairo_create()

    w = pixbuf.get_width()
    h = pixbuf.get_height()

    if alloc.width < w or alloc.height < h:
      self.set_size_request(w, h)
      return

    cr.translate(alloc.x, alloc.y)

    draw_rounded_box(cr, 0, 0,
        w, h,
        self._radius)
    cr.clip()

    Gdk.cairo_set_source_pixbuf(cr, pixbuf, 0, 0)
    cr.paint()