91
87
self.instrumentWindow.child.set_shadow_type(gtk.SHADOW_NONE)
90
self.header_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
91
self.header_size_group.add_widget(self.timelinebar.GetHeaderWidget())
94
93
self.hb = gtk.HBox()
95
94
self.hb.set_spacing(6)
95
self.hb.set_border_width(6)
96
96
self.vbox.pack_end(self.hb, False, False)
97
self.al = gtk.Alignment(0, 0, 1, 1)
97
self.vbox.pack_end(gtk.HSeparator(), False, False)
99
self.zoom_hb = gtk.HBox()
100
self.zoom_hb.set_spacing(6)
101
self.zoom_hb.set_border_width(0)
102
self.header_size_group.add_widget(self.zoom_hb)
98
104
self.scrollRange = gtk.Adjustment()
99
sb = gtk.HScrollbar(self.scrollRange)
101
self.al.set_padding(0, 0, 0, 0)
102
self.hb.pack_start(self.al)
105
self.scrollBar = gtk.HScrollbar(self.scrollRange)
107
self.hb.pack_start(self.zoom_hb, False, False)
108
self.hb.pack_start(self.scrollBar, True, True)
104
110
self.lastzoom = 0
106
#recording view contains zoom buttons
108
self.zoomSlider = gtk.HScale()
109
self.zoomSlider.set_size_request(70, -1)
111
self.zoomSlider.set_range(self.ZOOM_MIN_SCALE, self.ZOOM_MAX_SCALE)
112
self.zoomSlider.set_increments(0.2, 0.2)
113
self.zoomSlider.set_draw_value(False)
114
self.zoomSlider.set_value(self.project.viewScale)
115
self.zoomtip = gtk.Tooltips()
116
self.zoomtip.set_tip(self.zoomSlider, _("Zoom the timeline"),None)
118
self.zoomSlider.connect("value-changed", self.OnZoom)
120
inbutton = gtk.Button()
121
inimg = gtk.image_new_from_stock(gtk.STOCK_ZOOM_IN, gtk.ICON_SIZE_BUTTON)
122
inbutton.set_image(inimg)
123
inbutton.set_relief(gtk.RELIEF_NONE)
124
inbutton.connect("clicked", self.OnZoomIn)
126
outbutton = gtk.Button()
127
outimg = gtk.image_new_from_stock(gtk.STOCK_ZOOM_OUT, gtk.ICON_SIZE_BUTTON)
128
outbutton.set_image(outimg)
129
outbutton.set_relief(gtk.RELIEF_NONE)
130
outbutton.connect("clicked", self.OnZoomOut)
112
self.zoomSlider = gtk.HScale()
113
self.zoomSlider.set_size_request(70, -1)
115
self.zoomSlider.set_range(self.ZOOM_MIN_SCALE, self.ZOOM_MAX_SCALE)
116
self.zoomSlider.set_increments(0.2, 0.2)
117
self.zoomSlider.set_draw_value(False)
118
self.zoomSlider.set_value(self.project.viewScale)
119
self.zoomtip = gtk.Tooltips()
120
self.zoomtip.set_tip(self.zoomSlider, _("Zoom the timeline - Right-Click to reset to the default level"), None)
122
self.zoomSlider.connect("value-changed", self.OnZoom)
123
self.zoomSlider.connect("button-press-event", self.OnZoomReset)
125
self.inbutton = gtk.Button()
126
inimg = gtk.image_new_from_stock(gtk.STOCK_ZOOM_IN, gtk.ICON_SIZE_BUTTON)
127
self.inbutton.set_image(inimg)
128
self.inbutton.set_relief(gtk.RELIEF_NONE)
129
self.zoomtip.set_tip(self.inbutton, _("Zoom in timeline"), None)
130
self.inbutton.connect("clicked", self.OnZoomIn)
132
self.outbutton = gtk.Button()
133
outimg = gtk.image_new_from_stock(gtk.STOCK_ZOOM_OUT, gtk.ICON_SIZE_BUTTON)
134
self.outbutton.set_image(outimg)
135
self.outbutton.set_relief(gtk.RELIEF_NONE)
136
self.zoomtip.set_tip(self.outbutton, _("Zoom out timeline"), None)
137
self.outbutton.connect("clicked", self.OnZoomOut)
132
self.hb.pack_start( outbutton, False, False)
133
self.hb.pack_start( self.zoomSlider, False, False)
134
self.hb.pack_start( inbutton, False, False)
139
self.zoom_hb.pack_start( self.outbutton, False, False)
140
self.zoom_hb.pack_start( self.zoomSlider, False, False)
141
self.zoom_hb.pack_start( self.inbutton, False, False)
136
self.extraScrollTime = 25
137
143
self.centreViewOnPosition = False
138
144
self.scrollRange.lower = 0
139
145
self.scrollRange.upper = 100
140
146
self.scrollRange.value = 0
141
147
self.scrollRange.step_increment = 1
143
sb.connect("value-changed", self.OnScroll)
149
self.scrollBar.connect("value-changed", self.OnScroll)
144
150
self.connect("expose-event", self.OnExpose)
145
151
self.connect("button_release_event", self.OnExpose)
146
152
self.connect("button_press_event", self.OnMouseDown)
147
self.connect("size-allocate", self.OnAllocate)
154
#connect to the project signals
155
self.project.connect("gst-bus-error", self.OnProjectGstError)
156
self.project.connect("incremental-save", self.OnProjectIncSave)
157
self.project.connect("instrument::added", self.OnInstrumentAdded)
158
self.project.connect("instrument::reordered", self.OnInstrumentReordered)
159
self.project.connect("instrument::removed", self.OnInstrumentRemoved)
160
self.project.connect("view-start", self.OnViewStartChanged)
149
162
self.vbox.drag_dest_set( gtk.DEST_DEFAULT_DROP,
150
163
self.DRAG_TARGETS,
181
220
## use the new colormap
182
221
self.eventBox.set_style(stcp)
184
# calculate scrollable width - allow 4 pixels for borders
185
self.scrollRange.page_size = (self.allocation.width - Globals.INSTRUMENT_HEADER_WIDTH - 4) / self.project.viewScale
223
# calculate scrollable width (scroll bar should always be same width as viewable area)
224
self.scrollRange.page_size = (self.scrollBar.allocation.width) / self.project.viewScale
186
225
self.scrollRange.page_increment = self.scrollRange.page_size
187
226
# add EXTRA_SCROLL_TIME extra seconds
188
length = self.project.GetProjectLength() + self.extraScrollTime
227
length = self.project.GetProjectLength() + self.EXTRA_SCROLL_TIME
189
228
self.scrollRange.upper = length
191
230
if self.centreViewOnPosition:
192
231
self.centreViewOnPosition = False
193
232
#set the view to be centred over the playhead
194
233
start = self.project.transport.GetPosition() - (self.scrollRange.page_size / 2)
195
self.SetViewPosition(start)
234
self.project.SetViewStart(start)
196
235
# Need to adjust project view start if we are zooming out
197
236
# and the end of the project is now before the end of the page.
198
237
# Project end will be at right edge unless the start is also on
199
238
# screen, in which case the start will be at the left.
200
239
elif self.project.viewStart + self.scrollRange.page_size > length:
201
self.SetViewPosition(length - self.scrollRange.page_size)
204
#check the min zoom value (based on project length)
205
pixelSize = self.allocation.width - Globals.INSTRUMENT_HEADER_WIDTH - 4 # four pixels to account for borders
206
minScale = pixelSize / length
207
self.zoomSlider.set_range(minScale, self.ZOOM_MAX_SCALE)
208
if self.zoomSlider.get_value() < minScale:
209
self.zoomSlider.set_value(minScale)
211
#_____________________________________________________________________
213
def OnAllocate(self, widget, allocation):
215
Callback for "size-allocate" signal.
218
widget -- reserved for GTK callbacks, don't use it explicitly.
219
allocation -- new allocation value to be set.
221
self.allocation = allocation
223
#_____________________________________________________________________
228
Updates the GUI to reflect changes on the instruments, timeline and
230
Called either directly from OnStateChanged(), or via the owning
231
CompactMixView.update()(depending on which view we are in) when
232
there is a change of state in an instrument being listened to.
235
InstrumentViews MUST have the order that the instruments have in
236
Project.instruments, to keep the drag and drop of InstrumentViews
239
children = self.instrumentBox.get_children()
241
for instr in self.project.instruments:
242
#Find the InstrumentView that matches instr:
244
for ident, instrV in self.views:
245
if instrV.instrument is instr:
248
#If there is no InstrumentView for instr, create one:
250
iv = InstrumentViewer.InstrumentViewer(self.project, instr, self, self.mainview, self.small)
251
# if this is mix view then add parent (CompactMixView) as listener
254
instr.AddListener(self.mixView)
256
instr.AddListener(self)
258
self.views.append((instr.id, iv))
259
iv.headerAlign.connect("size-allocate", self.UpdateSize)
261
if iv not in children:
262
#Add the InstrumentView to the VBox
263
self.instrumentBox.pack_start(iv, False, False)
265
#If the InstrumentView has already been added, just move it
266
self.instrumentBox.reorder_child(iv, orderCounter)
268
#Make sure the InstrumentView is visible:
274
#self.views is up to date now
275
for ident, iv in self.views:
276
#check if instrument has been deleted
277
if not iv.instrument in self.project.instruments:
279
self.instrumentBox.remove(iv)
281
removeList.append((ident, iv))
283
iv.Update() #Update non-deleted instruments
285
#remove all the unused ones so the garbage collector can clean then up
286
for tuple_ in removeList:
287
self.views.remove(tuple_)
290
if len(self.views) > 0:
291
self.UpdateSize(None, self.views[0][1].headerAlign.get_allocation())
293
self.UpdateSize(None, None)
296
#_____________________________________________________________________
298
def UpdateSize(self, widget=None, size=None):
300
Called during update() to re-align the timeline and scrollbars
301
with the start of the event lane since the instrument width may
304
#find the width of the instrument headers (they should all be the same size)
306
tempWidth = size.width
308
tempWidth = self.INSTRUMENT_HEADER_WIDTH
310
#set it to the globals class
311
Globals.INSTRUMENT_HEADER_WIDTH = tempWidth
313
#align timeline and scrollbar
314
self.timelinebar.Update()
315
self.al.set_padding(0, 0, tempWidth, 0)
240
self.project.SetViewStart(length - self.scrollRange.page_size)
242
#check the min zoom value (based on project length)
243
# (scroll bar should always be same width as viewable area)
244
pixelSize = self.scrollBar.allocation.width
245
minScale = pixelSize / length
246
self.zoomSlider.set_range(minScale, self.ZOOM_MAX_SCALE)
247
if self.zoomSlider.get_value() < minScale:
248
self.zoomSlider.set_value(minScale)
250
#_____________________________________________________________________
252
def OnInstrumentAdded(self, project, instrument):
254
Callback for when an instrument is added to the project.
257
project -- The project that the instrument was added to.
258
instrument -- The instrument that was added.
260
instrViewer = InstrumentViewer.InstrumentViewer(project, instrument, self, self.mainview, self.small)
263
self.views.append((instrument.id, instrViewer))
264
self.header_size_group.add_widget(instrViewer.GetHeaderWidget())
266
self.instrumentBox.pack_start(instrViewer, False, False)
269
#_____________________________________________________________________
271
def OnInstrumentRemoved(self, project, instrument):
273
Callback for when an instrument is removed from the project.
276
project -- The project that the instrument was removed from.
277
instrument -- The instrument that was removed.
279
for ID, instrViewer in self.views:
280
if ID == instrument.id:
281
if instrViewer.parent:
282
self.instrumentBox.remove(instrViewer)
283
instrViewer.Destroy()
284
self.views.remove((ID, instrViewer))
287
#_____________________________________________________________________
289
def OnInstrumentReordered(self, project, instrument):
291
Callback for when an instrument's position in the project has changed.
294
project -- The project that the instrument was changed on.
295
instrument -- The instrument that was reordered.
297
for ID, instrViewer in self.views:
298
if ID == instrument.id:
299
if instrViewer.parent:
300
pos = self.project.instruments.index(instrument)
301
self.instrumentBox.reorder_child(instrViewer, pos)
302
instrViewer.show_all()
306
#_____________________________________________________________________
308
def OnProjectGstError(self, project, error, debug):
310
Callback for when the project sends a gstreamer error message
314
project -- The project instance that send the signal.
315
error -- The type of error that occurred as a string.
316
debug -- A string with more debug information about the error.
319
error = _("A Gstreamer error has occurred")
321
if not self.errorMessageArea:
322
msg_area = self.CreateDefaultErrorPane(error, debug)
323
self.vbox.pack_end(msg_area, False, False)
325
self.errorMessageArea = msg_area
327
#_____________________________________________________________________
329
def CreateDefaultErrorPane(self, error, details):
330
message = _("A GStreamer error has occurred.")
331
info = _("If this problem persists consider reporting a bug using the link in the help menu.")
333
details = "\n".join((error, info))
335
msg_area = MessageArea.MessageArea()
336
msg_area.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
337
msg_area.set_text_and_icon(gtk.STOCK_DIALOG_ERROR, message, details)
339
msg_area.connect("response", self.OnMessageAreaReponse, msg_area)
340
msg_area.connect("close", self.OnMessageAreaClose, msg_area)
344
#_____________________________________________________________________
346
def OnMessageAreaClose(self, widget, message_area):
347
if self.errorMessageArea:
348
self.vbox.remove(self.errorMessageArea)
349
self.errorMessageArea = None
351
#_____________________________________________________________________
353
def OnMessageAreaReponse(self, widget, response_id, message_area):
354
if response_id == gtk.RESPONSE_CLOSE:
355
self.OnMessageAreaClose(widget, message_area)
317
357
#_____________________________________________________________________
383
423
widget -- reserved for GTK callbacks, don't use it explicitly.
385
425
tmp = self.project.viewScale * 1.25
386
#setting the value will trigger the gtk event and call OnZoom for us.
426
#setting the value will trigger the "value-changed" signal and call OnZoom for us.
387
427
self.zoomSlider.set_value(tmp)
389
#_____________________________________________________________________
391
def SetViewPosition(self, position):
393
Moves the view so that the given position is the leftmost side
394
of the viewable area for scrolling, etc.
397
position -- the new position to set.
399
length = self.project.GetProjectLength() + self.extraScrollTime
400
#check if its over the project length
401
start = min(length - self.scrollRange.page_size, position)
402
#check if its under zero (do this after checking the project length, because if the project length is 0 it will go under)
403
start = max(0, start)
404
self.scrollRange.value = start
405
self.project.SetViewStart(start)
429
#_____________________________________________________________________
431
def OnZoomReset(self, widget, mouse):
433
Calls OnZoom when the user resets the zoom to the default by right-clicking.
436
widget -- reserved for GTK callbacks, don't use it explicitly.
437
mouse -- reserved for GTK callbacks, don't use it explicitly.
439
if mouse.button == 3:
440
tmp = (self.ZOOM_MAX_SCALE - self.ZOOM_MIN_SCALE) / 2
441
#setting the value will trigger the "value-changed" signal and call OnZoom for us.
442
self.zoomSlider.set_value(tmp)
445
#_____________________________________________________________________
447
def OnViewStartChanged(self, project):
449
Callback for when the project notifies that the
450
viewable start position has changed.
453
project -- The project instance that send the signal.
455
self.scrollRange.value = project.viewStart
407
457
#_____________________________________________________________________