Use PREFIX in install rule.
[SysBars.git] / barwidget.py
blob683a52dfd308aa95322ec50d4527d2d1f9ee9a13
1 import gobject
2 import gtk as g
4 # Orientation refers to orientation of bar, which is perpendicular to panel
5 HORIZ = g.ORIENTATION_HORIZONTAL
6 VERT = g.ORIENTATION_VERTICAL
8 class BarWidget(g.DrawingArea):
9 def __init__(self, desc, orient, caption, overlap = False,
10 pfd = None, length = -1):
11 self.desc = desc
12 self.orient = orient
13 self.length = length
14 self.total_width = desc.width
15 self.period = desc.min_period
16 self.reading = 0 # reading is scaled to window coords
17 self.gc = None
18 self.caption_gc = None
19 self.quiet = False
20 self.overlap = overlap
22 g.DrawingArea.__init__(self)
24 self.connect("size-allocate", self.size_allocate_cb)
25 self.connect("expose-event", self.expose_event_cb)
27 self.connect("style-set", self.style_set_cb)
28 self.connect("direction-changed", self.change_caption)
29 if pfd:
30 self.modify_font(pfd)
31 self.set_caption(caption)
33 if length != -1:
34 self.change_length(length)
35 gobject.timeout_add(int(self.period * 1000), self.tick_cb)
37 def set_caption(self, caption):
38 self.caption = caption
39 self.change_caption()
41 def style_set_cb(self, *args):
42 self.gc = None
43 self.caption_gc = None
44 self.change_caption()
46 def change_caption(self, *args):
47 self.caption_layout = self.create_pango_layout(self.caption)
48 extent = self.caption_layout.get_pixel_extents()[0]
49 self.caption_x = -extent[0]
50 self.caption_y = -extent[1]
51 self.caption_w = extent[2]
52 self.caption_h = extent[3]
53 if self.orient == HORIZ:
54 if self.total_width > self.caption_h:
55 width = self.total_width
56 else:
57 width = self.caption_h
58 else:
59 if self.total_width > self.caption_w:
60 width = self.total_width
61 else:
62 width = self.caption_w
63 self.cache_caption_offsets()
64 self.change_width(width)
66 def cache_caption_offsets(self, allocation = None):
67 if self.orient == HORIZ:
68 self.caption_x0 = self.caption_x + 1
69 if self.total_width > self.caption_h:
70 self.caption_y0 = self.caption_y + \
71 int((self.total_width - self.caption_h) / 2)
72 else:
73 self.caption_y0 = self.caption_y
74 else:
75 if not allocation:
76 allocation = self.get_allocation()
77 self.caption_y0 = allocation.height - self.caption_h + \
78 self.caption_y - 1
79 if self.total_width > self.caption_w:
80 self.caption_x0 = self.caption_x + \
81 int((self.total_width - self.caption_w) / 2)
82 else:
83 self.caption_x0 = self.caption_x
85 def size_allocate_cb(self, widget, allocation):
86 if self.orient == HORIZ:
87 self.length = allocation.width
88 cap = self.caption_w
89 self.total_width = allocation.height
90 else:
91 self.length = allocation.height
92 cap = self.caption_h
93 self.total_width = allocation.width
94 if not self.overlap:
95 self.length -= cap + 3
96 self.cache_caption_offsets(allocation)
98 def update_overlap(self, overlap):
99 self.overlap = overlap
100 self.size_allocate_cb(self, self.get_allocation())
101 self.queue_draw()
103 def scale_reading(self, reading):
104 min, max = self.desc.get_range()
105 if reading < min:
106 reading = min
107 if reading > max:
108 reading = max
109 return int(self.length * (reading - min) / (max - min))
111 def bar_edge(self):
112 return int((self.total_width - self.desc.width) / 2)
114 def mark_for_redraw(self, min_scaled, max_scaled):
115 if self.orient == HORIZ:
116 if not self.overlap:
117 min_scaled += self.caption_x + 3
118 self.queue_draw_area(min_scaled, self.bar_edge(),
119 max_scaled - min_scaled, self.desc.width)
120 else:
121 self.queue_draw_area(self.bar_edge(), self.length - max_scaled,
122 self.desc.width, max_scaled - min_scaled)
124 def tick_cb(self):
125 try:
126 reading = self.scale_reading(self.desc.get_reading())
127 except:
128 if not self.quiet:
129 self.quiet = True
130 # Hopefully this should be equivalent to returning False
131 # so we won't get any more ticks for this gauge, but use
132 # quiet flag in case
133 raise
134 reading = 0
135 if reading == self.reading:
136 period = self.period * 2
137 if period > self.desc.max_period:
138 period = self.desc.max_period
139 else:
140 if self.window and self.length > 0:
141 min_scaled = min(reading, self.reading)
142 max_scaled = max(reading, self.reading)
143 self.mark_for_redraw(min_scaled, max_scaled)
144 self.reading = reading
145 period = self.desc.min_period
146 if self.quiet:
147 return False
148 if period == self.period:
149 return True
150 else:
151 self.period = period
152 gobject.timeout_add(int(period * 1000), self.tick_cb)
153 return False
155 def expose_event_cb(self, widget, event):
156 if not self.caption_gc:
157 self.caption_gc = self.window.new_gc()
158 self.caption_gc.copy(self.get_style().fg_gc[g.STATE_NORMAL])
159 self.window.draw_layout(self.caption_gc,
160 self.caption_x0, self.caption_y0, self.caption_layout)
161 if self.orient == HORIZ:
162 if self.overlap:
163 x = 0
164 else:
165 x = self.caption_w + 3
166 filled_rect = g.gdk.Rectangle(x, self.bar_edge(),
167 self.reading, self.desc.width)
168 else:
169 filled_rect = g.gdk.Rectangle(self.bar_edge(),
170 self.length - self.reading,
171 self.desc.width, self.reading)
172 filled_rect = filled_rect.intersect(event.area)
173 if not self.gc:
174 self.gc = self.window.new_gc()
175 style = self.get_style()
176 self.gc.copy(style.fg_gc[g.STATE_NORMAL])
177 self.__update_gc_colour()
178 self.gc.set_function(g.gdk.XOR)
179 self.window.draw_rectangle(self.gc, True, *filled_rect)
180 return False
182 def __update_gc_colour(self):
183 style = self.get_style()
184 c1 = self.desc.colour
185 c2 = style.bg[g.STATE_NORMAL]
186 self.gc.set_rgb_fg_color(g.gdk.Color( \
187 c1.red ^ c2.red, c1.green ^ c2.green, c1.blue ^ c2.blue))
189 def change_colour(self, colour):
190 if self.gc:
191 self.__update_gc_colour()
192 self.queue_draw()
194 def change_width(self, width):
195 if self.orient == HORIZ:
196 self.set_size_request(self.length, width)
197 else:
198 self.set_size_request(width, self.length)
200 def change_length(self, length):
201 self.length = length
202 if self.orient == HORIZ:
203 self.set_size_request(length, self.total_width)
204 else:
205 self.set_size_request(self.total_width, length)
206 self.cache_caption_offsets()