1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 from button import DisableButton
24 from entry import Entry
25 from theme import ui_theme
26 import gobject
27 import gtk
28 from utils import (alpha_color_hex_to_cairo, cairo_disable_antialias,
29 color_hex_to_cairo,
30 propagate_expose, is_float, remove_timeout_id)
31
32
34 '''
35 SpinBox.
36
37 @undocumented: set_sensitive
38 @undocumented: size_change_cb
39 @undocumented: press_increase_button
40 @undocumented: press_decrease_button
41 @undocumented: handle_key_release
42 @undocumented: stop_update_value
43 @undocumented: increase_value
44 @undocumented: decrease_value
45 @undocumented: adjust_value
46 @undocumented: update
47 @undocumented: update_and_emit
48 @undocumented: expose_spin_bg
49 @undocumented: create_simple_button
50 '''
51
52 __gsignals__ = {
53 "value-changed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT,)),
54 "key-release" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT,)),
55 }
56
57 - def __init__(self,
58 value=0,
59 lower=0,
60 upper=100,
61 step=10,
62 default_width=55):
63 '''
64 Initialize SpinBox class.
65
66 @param value: Initialize value, default is 0.
67 @param lower: Lower value, default is 0.
68 @param upper: Upper value, default is 100.
69 @param step: Step value, default is 10.
70 @param default_width: Default with, default is 55 pixel.
71 '''
72 gtk.VBox.__init__(self)
73 self.current_value = value
74 self.lower_value = lower
75 self.upper_value = upper
76 self.step_value = step
77 self.update_delay = 100
78 self.increase_value_id = None
79 self.decrease_value_id = None
80
81
82 self.default_width = default_width
83 self.default_height = 22
84 self.arrow_button_width = 19
85 self.background_color = ui_theme.get_alpha_color("text_entry_background")
86 self.acme_color = ui_theme.get_alpha_color("text_entry_acme")
87 self.point_color = ui_theme.get_alpha_color("text_entry_point")
88 self.frame_point_color = ui_theme.get_alpha_color("text_entry_frame_point")
89 self.frame_color = ui_theme.get_alpha_color("text_entry_frame")
90
91
92 arrow_up_button = self.create_simple_button("up", self.press_increase_button)
93 arrow_down_button = self.create_simple_button("down", self.press_decrease_button)
94 button_box = gtk.VBox()
95 button_box.pack_start(arrow_up_button, False, False)
96 button_box.pack_start(arrow_down_button, False, False)
97 self.value_entry = Entry(str(value))
98 self.value_entry.check_text = is_float
99
100 self.main_align = gtk.Alignment()
101 self.main_align.set(0.5, 0.5, 0, 0)
102 hbox = gtk.HBox()
103 hbox.pack_start(self.value_entry, False, False)
104 hbox.pack_start(button_box, False, False)
105 hbox_align = gtk.Alignment()
106 hbox_align.set(0.5, 0.5, 1.0, 1.0)
107 hbox_align.set_padding(0, 1, 0, 0)
108 hbox_align.add(hbox)
109 self.main_align.add(hbox_align)
110 self.pack_start(self.main_align, False, False)
111
112
113 self.connect("size-allocate", self.size_change_cb)
114 self.main_align.connect("expose-event", self.expose_spin_bg)
115
117 '''
118 Internal function to wrap `set_sensitive`.
119 '''
120 super(SpinBox, self).set_sensitive(sensitive)
121 self.value_entry.set_sensitive(sensitive)
122
124 '''
125 Get current value.
126
127 @return: Return current value.
128 '''
129 return self.current_value
130
132 '''
133 Set value with given value.
134
135 @param value: New value.
136 '''
137 new_value = self.adjust_value(value)
138 if new_value != self.current_value:
139 self.update_and_emit(new_value)
140
142 '''
143 Emit `value-changed` signal.
144 '''
145 self.emit("value-changed", self.current_value)
146
148 '''
149 Get minimum value.
150 '''
151 return self.lower_value
152
154 '''
155 Set lower with given value.
156
157 @param value: New lower value.
158 '''
159 self.lower_value = value
160
162 '''
163 Get upper value.
164 '''
165 return self.upper_value
166
168 '''
169 Set upper with given value.
170
171 @param value: New upper value.
172 '''
173 self.upper_value = value
174
176 '''
177 Get step.
178 '''
179 return self.step_value
180
182 '''
183 Set step with given value.
184
185 @param value: New step value.
186 '''
187 self.set_step = value
188
190 '''
191 Internal callback for `size-allocate` signal.
192 '''
193 if rect.width > self.default_width:
194 self.default_width = rect.width
195
196 self.set_size_request(self.default_width, self.default_height)
197 self.value_entry.set_size_request(self.default_width - self.arrow_button_width, self.default_height - 2)
198
208
218
220 '''
221 Internal callback for `key-release-event` signal.
222 '''
223 self.stop_update_value()
224
225 self.emit("key-release", self.current_value)
226
228 '''
229 Internal function to stop update value.
230 '''
231 for timeout_id in [self.increase_value_id, self.decrease_value_id]:
232 remove_timeout_id(timeout_id)
233
235 '''
236 Internal function to increase valule.
237 '''
238 new_value = self.current_value + self.step_value
239 if new_value > self.upper_value:
240 new_value = self.upper_value
241 if new_value != self.current_value:
242 self.update_and_emit(new_value)
243
244 return True
245
247 '''
248 Internal function to decrease valule.
249 '''
250 new_value = self.current_value - self.step_value
251 if new_value < self.lower_value:
252 new_value = self.lower_value
253 if new_value != self.current_value:
254 self.update_and_emit(new_value)
255
256 return True
257
259 '''
260 Internal function to adjust value.
261 '''
262 if not isinstance(value, int):
263 return self.current_value
264 else:
265 if value < self.lower_value:
266 return self.lower_value
267 elif value > self.upper_value:
268 return self.upper_value
269 else:
270 return value
271
273 '''
274 Internal function to update value, just use when need avoid emit signal recursively.
275 '''
276 self.current_value = new_value
277 self.value_entry.set_text(str(self.current_value))
278
280 '''
281 Internal function to update new value and emit `value-changed` signal.
282 '''
283 self.current_value = new_value
284 self.value_entry.set_text(str(self.current_value))
285 self.emit("value-changed", self.current_value)
286
288 '''
289 Internal callback for `expose-event` signal.
290 '''
291
292 cr = widget.window.cairo_create()
293 rect = widget.allocation
294 x, y, w, h = rect.x, rect.y, rect.width, rect.height
295
296
297 with cairo_disable_antialias(cr):
298 cr.set_line_width(1)
299 if widget.state == gtk.STATE_INSENSITIVE:
300 cr.set_source_rgb(*color_hex_to_cairo(ui_theme.get_color("disable_frame").get_color()))
301 else:
302 cr.set_source_rgb(*color_hex_to_cairo(ui_theme.get_color("combo_entry_frame").get_color()))
303 cr.rectangle(rect.x, rect.y, rect.width, rect.height)
304 cr.stroke()
305
306 if widget.state == gtk.STATE_INSENSITIVE:
307 cr.set_source_rgba(*alpha_color_hex_to_cairo((ui_theme.get_color("disable_background").get_color(), 0.9)))
308 else:
309 cr.set_source_rgba(*alpha_color_hex_to_cairo((ui_theme.get_color("combo_entry_background").get_color(), 0.9)))
310 cr.rectangle(rect.x, rect.y, rect.width - 1, rect.height - 1)
311 cr.fill()
312
313 propagate_expose(widget, event)
314
315 return False
316
318 '''
319 Internal function to create simple button.
320 '''
321 button = DisableButton(
322 (ui_theme.get_pixbuf("spin/spin_arrow_%s_normal.png" % name),
323 ui_theme.get_pixbuf("spin/spin_arrow_%s_hover.png" % name),
324 ui_theme.get_pixbuf("spin/spin_arrow_%s_press.png" % name),
325 ui_theme.get_pixbuf("spin/spin_arrow_%s_disable.png" % name)),
326 )
327 if callback:
328 button.connect("button-press-event", callback)
329 button.connect("button-release-event", self.handle_key_release)
330 return button
331
332 gobject.type_register(SpinBox)
333