~timo-jyrinki/ubuntu/trusty/pitivi/backport_utopic_fixes

« back to all changes in this revision

Viewing changes to pitivi/ui/dynamic.py

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2011-05-26 15:29:58 UTC
  • mfrom: (3.1.20 experimental)
  • Revision ID: james.westby@ubuntu.com-20110526152958-90je1myzzjly26vw
Tags: 0.13.9.90-1ubuntu1
* Resynchronize on Debian
* debian/control:
  - Depend on python-launchpad-integration
  - Drop hal from Recommends to Suggests. This version has the patch applied
    to not crash without hal.
* debian/patches/01_lpi.patch:
  - launchpad integration  
* debian/rules:
  - Use gnome.mk so a translation template is built

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
import sys
30
30
import gst
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
33
34
import pango
 
35
from pitivi.ui.common import PADDING, SPACING
34
36
 
35
37
class DynamicWidget(object):
36
38
 
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
39
43
 
40
44
    def connectValueChanged(self, callback, *args):
41
45
        raise NotImplementedError
46
50
    def getWidgetValue(self, value):
47
51
        raise NotImplementedError
48
52
 
49
 
class DefaultWidget(gtk.Label):
 
53
    def getWidgetDefault(self):
 
54
        return self.default
 
55
 
 
56
    def setWidgetDefault(self, value):
 
57
        self.default = value
 
58
 
 
59
    def setWidgetToDefault(self):
 
60
        if self.default is not None:
 
61
            self.setWidgetValue(self.default)
 
62
 
 
63
class DefaultWidget(gtk.Label, DynamicWidget):
50
64
 
51
65
    """When all hope fails...."""
52
66
 
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)
 
70
 
55
71
 
56
72
    def connectValueChanged(self, callback, *args):
57
73
        pass
63
79
        return self.get_text()
64
80
 
65
81
 
66
 
class TextWidget(gtk.HBox):
 
82
class TextWidget(gtk.HBox, DynamicWidget):
67
83
 
68
84
    """A gtk.Entry which emits a value-changed signal only when its input is
69
85
    valid (matches the provided regex). If the input is invalid, a warning
80
96
    __INVALID__ = gtk.gdk.Color(0xFFFF, 0, 0)
81
97
    __NORMAL__ = gtk.gdk.Color(0, 0, 0)
82
98
 
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)
 
102
 
85
103
        self.set_border_width(0)
86
104
        self.set_spacing(0)
87
105
        if choices:
98
116
        self.matches = None
99
117
        self.last_valid = None
100
118
        self.valid = False
 
119
        self.send_signal = True
101
120
        self.text.connect("changed", self._textChanged)
102
121
        if matches:
103
122
            if type(matches) is str:
109
128
    def connectValueChanged(self, callback, *args):
110
129
        return self.connect("value-changed", callback, *args)
111
130
 
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)
114
134
 
115
135
    def getWidgetValue(self):
117
137
            return self.last_valid
118
138
        return self.text.get_text()
119
139
 
 
140
    def addChoices(self, choices):
 
141
        for choice in choices:
 
142
            self.combo.append_text(choice)
 
143
 
120
144
    def _textChanged(self, unused_widget):
121
145
        text = self.text.get_text()
122
146
        if self.matches:
123
147
            if self._filter(text):
124
148
                self.last_valid = text
125
 
                self.emit("value-changed")
 
149
                if self.send_signal:
 
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
130
155
                if self.valid:
131
156
                    self.text.set_icon_from_stock(1, gtk.STOCK_DIALOG_WARNING)
132
157
                self.valid = False
133
 
        else:
 
158
        elif self.send_signal:
134
159
            self.emit("value-changed")
135
160
 
 
161
        self.send_signal = True
 
162
 
136
163
    def _filter(self, text):
137
164
        match = self.matches.match(text)
138
165
        if match is not None:
139
166
            return True
140
167
        return False
141
168
 
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)
 
172
 
 
173
 
 
174
class NumericWidget(gtk.HBox, DynamicWidget):
143
175
 
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"""
147
179
 
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)
150
183
 
 
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):
 
188
        self._type = 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
159
195
 
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()
170
206
 
171
207
    def connectValueChanged(self, callback, *args):
172
208
        self.adjustment.connect("value-changed", callback, *args)
173
209
 
174
210
    def getWidgetValue(self):
 
211
        if self._type:
 
212
            return self._type(self.adjustment.get_value())
 
213
 
175
214
        return self.adjustment.get_value()
176
215
 
177
216
    def setWidgetValue(self, value):
178
217
        type_ = type(value)
179
 
        if type_ == int:
 
218
        if self._type is None:
 
219
            self._type = type_
 
220
 
 
221
        if type_ == int or type_ == long:
180
222
            minimum, maximum = (-sys.maxint, sys.maxint)
181
223
            step = 1.0
182
224
            page = 10.0
183
225
        elif type_ == float:
184
226
            minimum, maximum = (gobject.G_MINDOUBLE, gobject.G_MAXDOUBLE)
185
 
            step = 0.00001
186
 
            page = 0.01
 
227
            step = 0.01
 
228
            page = 0.1
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) -
194
 
            max(minimum, -1000))
195
 
 
196
 
class FractionWidget(TextWidget):
 
235
        self.spinner.set_adjustment(self.adjustment)
 
236
 
 
237
class TimeWidget(TextWidget, DynamicWidget):
 
238
    """ A widget that contains a time in nanosconds"""
 
239
 
 
240
    regex = re.compile("^([0-9]:[0-5][0-9]:[0-5][0-9])\.[0-9][0-9][0-9]$")
 
241
    __gtype_name__ = 'TimeWidget'
 
242
 
 
243
    def __init__(self, default=None):
 
244
        DynamicWidget.__init__(self, default)
 
245
        TextWidget.__init__(self, self.regex)
 
246
        TextWidget.set_width_chars(self, 10)
 
247
 
 
248
    def getWidgetValue(self):
 
249
        timecode = TextWidget.getWidgetValue(self)
 
250
 
 
251
        hh, mm, end = timecode.split(":")
 
252
        ss, xxx = end.split(".")
 
253
        nanosecs = int(hh) * 3.6 * 10e12 \
 
254
            + int(mm) * 6 * 10e10 \
 
255
            + int(ss) * 10e9 \
 
256
            + int(xxx) * 10e6
 
257
 
 
258
        nanosecs = nanosecs / 10 # Compensate the 10 factor of e notation
 
259
 
 
260
        return nanosecs
 
261
 
 
262
    def setWidgetValue(self, value, send_signal = True):
 
263
        TextWidget.setWidgetValue(self, time_to_string(value),
 
264
                                send_signal = send_signal)
 
265
 
 
266
    def connectFocusEvents (self, focusInCb, focusOutCb):
 
267
        fIn = self.text.connect ("button-press-event", focusInCb)
 
268
        fOut = self.text.connect ("focus-out-event", focusOutCb)
 
269
 
 
270
        return [fIn, fOut]
 
271
 
 
272
 
 
273
class FractionWidget(TextWidget, DynamicWidget):
197
274
 
198
275
    """A gtk.ComboBoxEntry """
199
276
 
201
278
        "^([0-9]*(\.[0-9]+)?)(([:/][0-9]*(\.[0-9]+)?)|M)?$")
202
279
    __gtype_name__ = 'FractionWidget'
203
280
 
204
 
    def __init__(self, range=None, presets=None):
 
281
    def __init__(self, range=None, presets=None, default=None):
 
282
        DynamicWidget.__init__(self, default)
 
283
 
205
284
        if range:
206
285
            flow = float(range.low)
207
286
            fhigh = float(range.high)
230
309
                return True
231
310
        return False
232
311
 
 
312
    def addPresets(self, presets):
 
313
        choices = []
 
314
        for preset in presets:
 
315
            if type(preset) is str:
 
316
                strval = preset
 
317
                preset = self._parseText(preset)
 
318
            else:
 
319
                strval = "%g:%g" % (preset.num, preset.denom)
 
320
            fpreset = float(preset)
 
321
            if self.low <= fpreset and fpreset <= self.high:
 
322
               choices.append(strval)
 
323
 
 
324
        self.addChoices(choices)
 
325
 
233
326
    def setWidgetValue(self, value):
234
327
        if type(value) is str:
235
328
            value = self._parseText(value)
262
355
                denom = float(groups[2][1:])
263
356
        return gst.Fraction(num, denom)
264
357
 
265
 
class ToggleWidget(gtk.CheckButton):
 
358
class ToggleWidget(gtk.CheckButton, DynamicWidget):
266
359
 
267
360
    """A gtk.CheckButton which supports the DynamicWidget interface."""
268
361
 
269
 
    def __init__(self):
 
362
    def __init__(self, default=None):
270
363
        gtk.CheckButton.__init__(self)
 
364
        DynamicWidget.__init__(self, default)
271
365
 
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()
280
374
 
281
 
class ChoiceWidget(gtk.HBox):
 
375
class ChoiceWidget(gtk.HBox, DynamicWidget):
282
376
 
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."""
286
380
 
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()
319
414
        else:
320
415
            self.contents.set_sensitive(True)
321
416
 
322
 
class PresetChoiceWidget(gtk.HBox):
 
417
class PresetChoiceWidget(gtk.HBox, DynamicWidget):
323
418
 
324
419
    """A popup which manages preset settings on a group of widgets supporting
325
420
    the dynamic interface"""
357
452
        def unmap(self):
358
453
            return [w.getWidgetValue() for w in self.widgets if w]
359
454
 
360
 
    def __init__(self, presets):
 
455
    def __init__(self, presets, default=None):
361
456
        gtk.HBox.__init__(self)
 
457
        DynamicWidget.__init__(self, default)
362
458
        self._block_update = False
363
459
        self._widget_map = None
364
460
 
444
540
        self.combo.set_active(preset_index)
445
541
 
446
542
 
447
 
class PathWidget(gtk.FileChooserButton):
 
543
class PathWidget(gtk.FileChooserButton, DynamicWidget):
448
544
 
449
545
    """A gtk.FileChooserButton which supports the DynamicWidget interface."""
450
546
 
456
552
            ()),
457
553
    }
458
554
 
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(
461
558
            action = action,
462
559
            buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_CLOSE,
483
580
            self.emit("value-changed")
484
581
            self.dialog.hide()
485
582
 
486
 
class ColorWidget(gtk.ColorButton):
 
583
class ColorWidget(gtk.ColorButton, DynamicWidget):
487
584
 
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)
492
590
 
521
619
            return color
522
620
        return color.to_string()
523
621
 
524
 
class FontWidget(gtk.FontButton):
 
622
class FontWidget(gtk.FontButton, DynamicWidget):
525
623
 
526
 
    def __init__(self):
 
624
    def __init__(self, default = None):
527
625
        gtk.FontButton.__init__(self)
 
626
        DynamicWidget.__init__(self, default)
528
627
        self.set_use_font(True)
529
628
 
530
629
    def connectValueChanged(self, callback, *args):
536
635
    def getWidgetValue(self):
537
636
        return self.get_font_name()
538
637
 
539
 
class ResolutionWidget(gtk.HBox):
 
638
class ResolutionWidget(gtk.HBox, DynamicWidget):
540
639
 
541
 
    def __init__ (self):
 
640
    def __init__ (self, default = None):
542
641
        gtk.HBox.__init__(self)
 
642
        DynamicWidget.__init__(self, default)
543
643
        self.props.spacing = 6
544
644
 
545
645
        self.dwidth = 0
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),
593
693
            (
594
694
                gst.FractionRange(
595
 
                    gst.Fraction(1, 1), 
 
695
                    gst.Fraction(1, 1),
596
696
                    gst.Fraction(30000, 1001)
597
697
                ),
598
698
                (
599
 
                    "25:1", 
 
699
                    "25:1",
600
700
                    gst.Fraction(30,1),
601
701
                    "30M",
602
702
                ),