31
31
from gettext import gettext as _
32
from pitivi.utils import time_to_string
32
33
from pitivi.ui.common import unpack_color, pack_color_32, pack_color_64
35
from pitivi.ui.common import PADDING, SPACING
35
37
class DynamicWidget(object):
37
39
"""An interface which provides a uniform way to get, set, and observe
38
40
widget properties"""
41
def __init__(self, default):
42
self.default = default
40
44
def connectValueChanged(self, callback, *args):
41
45
raise NotImplementedError
46
50
def getWidgetValue(self, value):
47
51
raise NotImplementedError
49
class DefaultWidget(gtk.Label):
53
def getWidgetDefault(self):
56
def setWidgetDefault(self, value):
59
def setWidgetToDefault(self):
60
if self.default is not None:
61
self.setWidgetValue(self.default)
63
class DefaultWidget(gtk.Label, DynamicWidget):
51
65
"""When all hope fails...."""
53
def __init__(self, *unused, **kw_unused):
67
def __init__(self, default = None, *unused, **kw_unused):
54
68
gtk.Label.__init__(self, _("Implement Me"))
69
DynamicWidget.__init__(self, default)
56
72
def connectValueChanged(self, callback, *args):
80
96
__INVALID__ = gtk.gdk.Color(0xFFFF, 0, 0)
81
97
__NORMAL__ = gtk.gdk.Color(0, 0, 0)
83
def __init__(self, matches = None, choices = None):
99
def __init__(self, matches = None, choices = None, default = None):
84
100
gtk.HBox.__init__(self)
101
DynamicWidget.__init__(self, default)
85
103
self.set_border_width(0)
86
104
self.set_spacing(0)
109
128
def connectValueChanged(self, callback, *args):
110
129
return self.connect("value-changed", callback, *args)
112
def setWidgetValue(self, value):
131
def setWidgetValue(self, value, send_signal = True):
132
self.send_signal = send_signal
113
133
self.text.set_text(value)
115
135
def getWidgetValue(self):
117
137
return self.last_valid
118
138
return self.text.get_text()
140
def addChoices(self, choices):
141
for choice in choices:
142
self.combo.append_text(choice)
120
144
def _textChanged(self, unused_widget):
121
145
text = self.text.get_text()
123
147
if self._filter(text):
124
148
self.last_valid = text
125
self.emit("value-changed")
150
self.emit("value-changed")
126
151
if not self.valid:
127
152
self.text.set_icon_from_stock(1, None)
128
153
self.valid = True
131
156
self.text.set_icon_from_stock(1, gtk.STOCK_DIALOG_WARNING)
132
157
self.valid = False
158
elif self.send_signal:
134
159
self.emit("value-changed")
161
self.send_signal = True
136
163
def _filter(self, text):
137
164
match = self.matches.match(text)
138
165
if match is not None:
142
class NumericWidget(gtk.HBox):
169
def set_width_chars(self, width):
170
"""Allows setting the width of the text entry widget for compactness."""
171
self.text.set_width_chars(width)
174
class NumericWidget(gtk.HBox, DynamicWidget):
144
176
"""A gtk.HScale and a gtk.SpinButton which share an adjustment. The
145
177
SpinButton is always displayed, while the HScale only appears if both
146
178
lower and upper bounds are defined"""
148
def __init__(self, upper = None, lower = None):
180
def __init__(self, upper = None, lower = None, default=None):
149
181
gtk.HBox.__init__(self)
182
DynamicWidget.__init__(self, default)
184
self.spacing = SPACING
151
185
self.adjustment = gtk.Adjustment()
152
186
self.upper = upper
153
187
self.lower = lower
154
if (upper != None) and (lower != None):
189
if (upper != None) and (lower != None) and\
190
(upper < 5000) and (lower > -5000):
155
191
self.slider = gtk.HScale(self.adjustment)
156
self.pack_end(self.slider)
192
self.pack_start(self.slider, fill=True, expand=True)
157
193
self.slider.show()
158
194
self.slider.props.draw_value = False
165
201
self.adjustment.props.lower = lower
166
202
self.adjustment.props.upper = upper
167
203
self.spinner = gtk.SpinButton(self.adjustment)
168
self.pack_start(self.spinner)
204
self.pack_end(self.spinner, expand=not hasattr(self, 'slider'))
169
205
self.spinner.show()
171
207
def connectValueChanged(self, callback, *args):
172
208
self.adjustment.connect("value-changed", callback, *args)
174
210
def getWidgetValue(self):
212
return self._type(self.adjustment.get_value())
175
214
return self.adjustment.get_value()
177
216
def setWidgetValue(self, value):
178
217
type_ = type(value)
218
if self._type is None:
221
if type_ == int or type_ == long:
180
222
minimum, maximum = (-sys.maxint, sys.maxint)
183
225
elif type_ == float:
184
226
minimum, maximum = (gobject.G_MINDOUBLE, gobject.G_MAXDOUBLE)
187
229
self.spinner.props.digits = 2
188
230
if self.lower is not None:
189
231
minimum = self.lower
190
232
if self.upper is not None:
191
233
maximum = self.upper
192
234
self.adjustment.set_all(value, minimum, maximum, step, page, 0)
193
self.spinner.props.climb_rate = 0.01 * abs(min(maximum, 1000) -
196
class FractionWidget(TextWidget):
235
self.spinner.set_adjustment(self.adjustment)
237
class TimeWidget(TextWidget, DynamicWidget):
238
""" A widget that contains a time in nanosconds"""
240
regex = re.compile("^([0-9]:[0-5][0-9]:[0-5][0-9])\.[0-9][0-9][0-9]$")
241
__gtype_name__ = 'TimeWidget'
243
def __init__(self, default=None):
244
DynamicWidget.__init__(self, default)
245
TextWidget.__init__(self, self.regex)
246
TextWidget.set_width_chars(self, 10)
248
def getWidgetValue(self):
249
timecode = TextWidget.getWidgetValue(self)
251
hh, mm, end = timecode.split(":")
252
ss, xxx = end.split(".")
253
nanosecs = int(hh) * 3.6 * 10e12 \
254
+ int(mm) * 6 * 10e10 \
258
nanosecs = nanosecs / 10 # Compensate the 10 factor of e notation
262
def setWidgetValue(self, value, send_signal = True):
263
TextWidget.setWidgetValue(self, time_to_string(value),
264
send_signal = send_signal)
266
def connectFocusEvents (self, focusInCb, focusOutCb):
267
fIn = self.text.connect ("button-press-event", focusInCb)
268
fOut = self.text.connect ("focus-out-event", focusOutCb)
273
class FractionWidget(TextWidget, DynamicWidget):
198
275
"""A gtk.ComboBoxEntry """
201
278
"^([0-9]*(\.[0-9]+)?)(([:/][0-9]*(\.[0-9]+)?)|M)?$")
202
279
__gtype_name__ = 'FractionWidget'
204
def __init__(self, range=None, presets=None):
281
def __init__(self, range=None, presets=None, default=None):
282
DynamicWidget.__init__(self, default)
206
285
flow = float(range.low)
207
286
fhigh = float(range.high)
262
355
denom = float(groups[2][1:])
263
356
return gst.Fraction(num, denom)
265
class ToggleWidget(gtk.CheckButton):
358
class ToggleWidget(gtk.CheckButton, DynamicWidget):
267
360
"""A gtk.CheckButton which supports the DynamicWidget interface."""
362
def __init__(self, default=None):
270
363
gtk.CheckButton.__init__(self)
364
DynamicWidget.__init__(self, default)
272
366
def connectValueChanged(self, callback, *args):
273
367
self.connect("toggled", callback, *args)
278
372
def getWidgetValue(self):
279
373
return self.get_active()
281
class ChoiceWidget(gtk.HBox):
375
class ChoiceWidget(gtk.HBox, DynamicWidget):
283
377
"""Abstractly, represents a choice between a list of named values. The
284
378
association between value names and values is arbitrary. The current
285
379
implementation uses a gtk.ComboBox."""
287
def __init__(self, choices):
381
def __init__(self, choices, default=None):
288
382
gtk.HBox.__init__(self)
383
DynamicWidget.__init__(self, default)
289
384
self.choices = None
290
385
self.values = None
291
386
self.contents = gtk.combo_box_new_text()
459
def __init__(self, action = gtk.FILE_CHOOSER_ACTION_OPEN):
555
def __init__(self, action = gtk.FILE_CHOOSER_ACTION_OPEN, default=None):
556
DynamicWidget.__init__(self, default)
460
557
self.dialog = gtk.FileChooserDialog(
462
559
buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_CLOSE,
483
580
self.emit("value-changed")
484
581
self.dialog.hide()
486
class ColorWidget(gtk.ColorButton):
583
class ColorWidget(gtk.ColorButton, DynamicWidget):
488
def __init__(self, value_type=str):
585
def __init__(self, value_type=str, default= None):
489
586
gtk.ColorButton.__init__(self)
587
DynamicWidget.__init__(self, default)
490
588
self.value_type = value_type
491
589
self.set_use_alpha(True)
522
620
return color.to_string()
524
class FontWidget(gtk.FontButton):
622
class FontWidget(gtk.FontButton, DynamicWidget):
624
def __init__(self, default = None):
527
625
gtk.FontButton.__init__(self)
626
DynamicWidget.__init__(self, default)
528
627
self.set_use_font(True)
530
629
def connectValueChanged(self, callback, *args):
586
686
("pear", "pear")),)),
587
687
(ColorWidget, 0x336699FF, (int,)),
588
688
(FontWidget, "Sans 9", ()),
589
(FractionWidget, "30M",
590
(gst.FractionRange(gst.Fraction(1, 1),
689
(FractionWidget, "30M",
690
(gst.FractionRange(gst.Fraction(1, 1),
591
691
gst.Fraction(30000, 1001)),)),
592
(FractionWidget, gst.Fraction(25000, 1001),
692
(FractionWidget, gst.Fraction(25000, 1001),
594
694
gst.FractionRange(
596
696
gst.Fraction(30000, 1001)
600
700
gst.Fraction(30,1),