~jconti/recent-notifications/trunk

201 by Jason Conti
Using a bit of cairo to display icons with rounded edges and message items with rounded backgrounds. Still need to get the proper colors from the gtk theme and possibly add options for custom colors.
1
"""
2
RoundedWidgets.py
3
April 22, 2011
4
5
Custom widgets that have rounded edges
6
"""
7
8
import logging
9
import math
10
11
from gi.repository import Gdk, GdkPixbuf, GObject, Gtk
12
203 by Jason Conti
Adding Theme.py in preparation for adding color themes, and updated RoundedBox to use the new Color class.
13
from Theme import Color
14
201 by Jason Conti
Using a bit of cairo to display icons with rounded edges and message items with rounded backgrounds. Still need to get the proper colors from the gtk theme and possibly add options for custom colors.
15
logger = logging.getLogger("RoundedWidgets")
16
17
# Angles in pi/2 increments 
18
A0 = 0
19
A1 = math.pi / 2.0
20
A2 = math.pi
21
A3 = 3.0 * math.pi / 2.0
22
A4 = 2.0 * math.pi
23
24
def draw_rounded_box(cr, x, y, width, height, radius):
25
  """Draws a rounded box to a cairo context, but doesn't fill or stroke it
26
  so it can be used as a clipping region as well."""
27
  x1 = x
28
  y1 = y
29
  w = width
30
  h = height
31
  x2 = x1 + w
32
  y2 = y1 + h
33
  r = radius
34
35
  cr.move_to(x1 + r, y1)
36
  cr.line_to(x2 - r, y1)
37
  cr.arc(x2 - r, y1 + r, r, A3, A4)
38
  cr.line_to(x2, y2 - r)
39
  cr.arc(x2 - r, y2 - r, r, A0, A1)
40
  cr.line_to(x1 + r, y2)
41
  cr.arc(x1 + r, y2 - r, r, A1, A2)
42
  cr.line_to(x1, y1 + r)
43
  cr.arc(x1 + r, y1 + r, r, A2, A3)
44
45
class RoundedBox(Gtk.Box):
46
  """A simple container that draws a solid background with rounded edges"""
207 by Jason Conti
Setting most of the colors with a gtk rc style now, except RoundedBox, because I can't figure out how to get the background style color. Seems like it should be widget.style.bg[state] however that list is always empty.
47
  BACKGROUND_COLOR = Color("#fff")
203 by Jason Conti
Adding Theme.py in preparation for adding color themes, and updated RoundedBox to use the new Color class.
48
  def __init__(self, radius = 10):
201 by Jason Conti
Using a bit of cairo to display icons with rounded edges and message items with rounded backgrounds. Still need to get the proper colors from the gtk theme and possibly add options for custom colors.
49
    GObject.GObject.__init__(self)
50
51
    self._radius = radius
52
53
    self.set_double_buffered(False)
54
    self.set_redraw_on_allocate(True)
55
56
  def set_radius(self, radius):
57
    """Sets the radius of the curved edges of this box"""
58
    self._radius = radius
59
    self.queue_draw()
60
61
  def get_radius(self):
62
    """Gets the radius of the curved edges of this box"""
63
    return self._radius
64
65
  def do_expose_event(self, event):
66
    """Draws the background and propagates the event to the children"""
67
    window = self.get_window()
68
    alloc = self.get_allocation()
69
    cr = window.cairo_create()
70
71
    # Set the clipping region
72
    cr.rectangle(event.area.x, event.area.y, event.area.width,
73
        event.area.height)
74
    cr.clip()
75
207 by Jason Conti
Setting most of the colors with a gtk rc style now, except RoundedBox, because I can't figure out how to get the background style color. Seems like it should be widget.style.bg[state] however that list is always empty.
76
    #TODO: Fix this hack
77
    color = RoundedBox.BACKGROUND_COLOR
78
    cr.set_source_rgb(color.red, color.green, color.blue)
201 by Jason Conti
Using a bit of cairo to display icons with rounded edges and message items with rounded backgrounds. Still need to get the proper colors from the gtk theme and possibly add options for custom colors.
79
80
    # Draw the rounded box
81
    draw_rounded_box(cr, alloc.x, alloc.y, alloc.width, alloc.height,
82
        self._radius)
83
    cr.fill()
84
85
    # Propagate the event to the children
86
    for child in self.get_children():
87
      self.propagate_expose(child, event)
88
89
class RoundedIcon(Gtk.Widget):
90
  """Draws a pixbuf with rounded edges"""
91
  def __init__(self, pixbuf = None, radius = 10):
92
    GObject.GObject.__init__(self)
93
94
    self._pixbuf = pixbuf
95
    self._radius = radius
96
97
    self.set_has_window(False)
98
    self.set_double_buffered(False)
99
    self.set_redraw_on_allocate(True)
100
101
  def set_from_pixbuf(self, pixbuf):
102
    """Sets the icon from a pixbuf"""
103
    self._pixbuf = pixbuf
104
105
  def do_expose_event(self, event):
106
    """Draws the pixbuf"""
107
    pixbuf = self._pixbuf
108
    if pixbuf == None:
109
      return
110
111
    window = self.get_window()
112
    alloc = self.get_allocation()
113
    cr = window.cairo_create()
114
115
    w = pixbuf.get_width()
116
    h = pixbuf.get_height()
117
118
    if alloc.width < w or alloc.height < h:
119
      self.set_size_request(w, h)
120
      return
121
122
    cr.translate(alloc.x, alloc.y)
123
124
    draw_rounded_box(cr, 0, 0,
125
        w, h,
126
        self._radius)
127
    cr.clip()
128
129
    Gdk.cairo_set_source_pixbuf(cr, pixbuf, 0, 0)
130
    cr.paint()
131