1 import maya.api.OpenMayaUI
as omui
2 import maya.api.OpenMaya
as om
16 custom_sequencer_drawers = globals().get(
'custom_sequencer_drawers',
None)
20 maya_exit_callback_id = globals().get(
'maya_exit_callback_id',
None)
23 class CustomSequencerDrawer:
25 Base class for drawing objects
29 self.manager = omui.MSequencerCustomDrawManager()
31 self.init_draw_objects()
34 self.clear_primitives()
36 for draw_id
in self.draw_ids:
37 self.manager.deregisterCustomDraw(draw_id)
39 def create_timeline_draw_object(
40 self, name, tooltip, draw_layer, bg_color=
None
43 Creates and registers a custom timeline draw object with the sequencer
46 draw_id = self.manager.registerCustomDrawTimeline(
53 self.manager.setBackgroundColor(draw_id, om.MColor(bg_color))
55 self.draw_ids.append(draw_id)
58 def create_track_title_draw_object(
59 self, name, tooltip, draw_layer, trackNumber,
60 is_audio=
False, bg_color=
None
63 Creates and registers a custom track title draw object with the
64 sequencer draw manager.
66 draw_id = self.manager.registerCustomDrawTrack(
67 omui.MSequencerCustomDrawManager.kTrackTitle,
75 self.set_track_properties(draw_id, bg_color)
78 def create_track_draw_object(
79 self, name, tooltip, draw_layer, trackNumber,
80 is_audio=
False, bg_color=
None
83 Creates and registers a custom track draw object with the sequencer
86 draw_id = self.manager.registerCustomDrawTrack(
87 omui.MSequencerCustomDrawManager.kTrack,
95 self.set_track_properties(draw_id, bg_color)
98 def set_track_properties(
99 self, draw_id, bg_color=
None
102 Setup common attributes between track and track title draw objects
105 self.manager.setBackgroundColor(draw_id, om.MColor(bg_color))
107 self.draw_ids.append(draw_id)
111 def bracket_primitive(
112 cls, start, stop, color, bottom, height, priority, label=
''
114 prim = omui.MSequencerDrawPrimitive(
115 omui.MSequencerDrawPrimitive.kBracket,
116 om.MTime(start), om.MTime(stop), om.MColor(color),
117 bottom, height, priority, label
123 def upper_outline_primitive(
124 cls, start, stop, color, bottom, height, priority, label=
''
126 prim = omui.MSequencerDrawPrimitive(
127 omui.MSequencerDrawPrimitive.kUpperOutline,
128 om.MTime(start), om.MTime(stop), om.MColor(color),
129 bottom, height, priority, label
135 def full_outline_primitive(
136 cls, start, stop, color, bottom, height, priority, label=
''
138 prim = omui.MSequencerDrawPrimitive(
139 omui.MSequencerDrawPrimitive.kFullOutline,
140 om.MTime(start), om.MTime(stop), om.MColor(color),
141 bottom, height, priority, label
147 def vertical_line_primitive(
148 cls, time, color, bottom, height, priority, label=
''
150 prim = omui.MSequencerDrawPrimitive(
151 omui.MSequencerDrawPrimitive.kVerticalLine,
152 om.MTime(time), om.MTime(time), om.MColor(color),
153 bottom, height, priority, label
159 def filled_rect_primitive(
160 cls, start, stop, color, bottom, height, priority, label=
''
162 prim = omui.MSequencerDrawPrimitive(
163 omui.MSequencerDrawPrimitive.kFilledRect,
164 om.MTime(start), om.MTime(stop), om.MColor(color),
165 bottom, height, priority, label
172 cls, time, color, bottom, height, priority, label
174 prim = omui.MSequencerDrawPrimitive(
175 omui.MSequencerDrawPrimitive.kText,
176 om.MTime(time), om.MTime(time), om.MColor(color),
177 bottom, height, priority, label
182 def init_draw_objects(self):
185 def clear_primitives(self):
186 manager = omui.MSequencerCustomDrawManager()
188 for draw_id
in self.draw_ids:
189 manager.clearDrawPrimitives(draw_id)
191 manager.requestSequencerRedraw()
194 class SequencerTimelineDrawDemo(CustomSequencerDrawer):
196 Demo custom drawing in the Sequencer timeline area.
201 self.rgb_bg_color = [1.0, 1.0, 1.0]
204 def init_draw_objects(self):
205 manager = omui.MSequencerCustomDrawManager()
206 self.init_bg_draw_object(manager)
207 self.init_fg_draw_object(manager)
209 def init_bg_draw_object(self, manager):
211 Setup draw object for sequencer timeline background
212 This object will be drawn before/behind the ticks and frame numbers
214 draw_id = self.create_timeline_draw_object(
215 'custom draw timeline 1',
216 'My custom draw on timeline BG tooltip',
218 bg_color=[0.1, 0.3, 0.1, 0.25]
220 manager.setStartPrimitiveEditFunction(draw_id, self.startEdit)
221 manager.setEditPrimitiveFunction(draw_id, self.editing)
222 manager.setSetCopyPrimitivesFunction(draw_id, self.setCopying)
223 manager.setStopPrimitiveEditFunction(draw_id, self.stopEdit)
225 self.bg_draw_id = draw_id
226 self.update_bg_primitives(manager)
228 def init_fg_draw_object(self, manager):
230 Setup draw object for sequencer timeline foreground
231 This object will be drawn over the ticks and frame numbers
233 self.fg_draw_id = self.create_timeline_draw_object(
234 'custom draw timeline 2',
239 self.update_fg_primitives(manager)
241 def update_bg_primitives(self, manager):
243 Create primitives for background timeline draw object
246 CustomSequencerDrawer.full_outline_primitive(
247 52, 615, [0.2, 0.8, 0.2],
248 bottom=0.05, height=0.9, priority=1
250 CustomSequencerDrawer.bracket_primitive(
251 65, 175, [0.8, 0.2, 0.2],
252 bottom=0.2, height=0.7, priority=10,
253 label=
'Timeline BG Bracket'
255 CustomSequencerDrawer.upper_outline_primitive(
256 311, 353, [0.8, 0.8, 0.2],
257 bottom=0.25, height=0.5, priority=1
259 CustomSequencerDrawer.full_outline_primitive(
260 405, 457, [0.8, 0.8, 0.8],
261 bottom=0.1, height=0.75, priority=1
263 CustomSequencerDrawer.vertical_line_primitive(
264 515, [0.8, 0.1, 0.9],
265 bottom=0, height=1, priority=1
269 prim = CustomSequencerDrawer.filled_rect_primitive(
270 210, 300, self.rgb_bg_color,
271 bottom=0.1, height=0.75, priority=1
274 prim.tooltip =
'Filled Rect Tooltip'
275 prim.setBuildMenuFunction(self.make_menu)
278 manager.setDrawPrimitives(self.bg_draw_id, prims)
279 manager.requestSequencerRedraw()
281 def make_menu(self, parent_id, time):
282 cmds.setParent(parent_id, menu=
True)
283 cmds.menuItem(label=f
'Randomize color {time}',
284 command=self.randomize_bg_color)
286 def randomize_bg_color(self, *args):
287 print(
"Randomizing background color")
288 self.rgb_bg_color = [random.random(), random.random(), random.random()]
289 self.update_bg_primitives(omui.MSequencerCustomDrawManager())
291 def update_fg_primitives(self, manager):
293 Create primitives for foreground timeline draw object
296 CustomSequencerDrawer.filled_rect_primitive(
297 -100, -12, [0.8, 0.8, 0.2],
298 bottom=0.25, height=0.5, priority=1
300 CustomSequencerDrawer.full_outline_primitive(
301 -210, -2, [0.8, 0.8, 0.8],
302 bottom=0.1, height=0.75, priority=1
304 CustomSequencerDrawer.text_primitive(
305 -200, [1, 1, 1], bottom=0.1, height=0.75, priority=1,
306 label=
'Timeline FG Draw Object'),
309 manager.setDrawPrimitives(self.fg_draw_id, prims)
311 def startEdit(self, time):
312 print(f
"Start editing at time {time}")
314 def editing(self, time, currentTime):
315 print(f
"Editing at time {time}, currentTime={currentTime}")
318 print(
"Stop editing")
320 def setCopying(self, copying):
321 print(f
"Set copying to {copying}")
324 class ShotTrackTitleDrawDemo(CustomSequencerDrawer):
326 Demo custom drawing in the Sequencer track title region for a shot track.
335 def init_draw_objects(self):
336 manager = omui.MSequencerCustomDrawManager()
338 draw_id = self.create_track_title_draw_object(
339 'custom draw track title',
340 'My Custom Draw Track Title Tooltip',
343 bg_color=[1.0, 0.3, 0.1, 0.5]
346 manager.setStartPrimitiveEditFunction(draw_id, self.startEdit)
347 manager.setEditPrimitiveFunction(draw_id, self.editing)
348 manager.setSetCopyPrimitivesFunction(draw_id, self.setCopying)
349 manager.setStopPrimitiveEditFunction(draw_id, self.stopEdit)
351 self.update_primitives(manager, draw_id)
352 self.draw_id = draw_id
354 def update_primitives(self, manager, draw_id):
356 CustomSequencerDrawer.filled_rect_primitive(
357 self.start + self.edit_delta,
358 self.start + self.edit_delta + 80,
359 [0.2, 0.8, 0.2, 0.75],
361 height=0.5
if self.toggled
else 0.75,
365 prims[-1].tooltip =
'Track Title Filled Rect Tooltip Text'
367 def sample_menu_item(self, *args):
368 self.toggled =
not self.toggled
369 self.update_primitives(manager, draw_id)
371 def make_menu(self, parent_id, time):
372 cmds.setParent(parent_id, menu=
True)
373 cmds.menuItem(label=
'Toggle Height',
375 command=
lambda *args: sample_menu_item(self, *args))
377 prims[-1].setBuildMenuFunction(
378 lambda parent_id, time: make_menu(self, parent_id, time))
380 manager.setDrawPrimitives(draw_id, prims)
381 manager.requestSequencerRedraw()
383 def startEdit(self, x):
384 print(f
"Start editing track title at x {x}")
387 def editing(self, delta, current_x):
388 print(f
"Editing track title at time {delta}, currentTime={current_x}")
389 self.edit_delta = delta.value
390 self.update_primitives(omui.MSequencerCustomDrawManager(), self.draw_id)
393 print(
"Stop editing track title")
394 self.start += self.edit_delta
396 self.update_primitives(omui.MSequencerCustomDrawManager(), self.draw_id)
398 def setCopying(self, copying):
399 print(f
"Set copying to {copying} for track title")
402 class ShotTrackDrawDemo(CustomSequencerDrawer):
404 Demo custom drawing in the Sequencer for a shot track.
407 self.edit_delta =
None
408 self.edit_copy =
False
409 self.fg_start = om.MTime(-60)
415 self.fg_edit_prim =
None
418 def init_draw_objects(self):
419 manager = omui.MSequencerCustomDrawManager()
421 self.bg_draw_id = self.create_track_draw_object(
422 'custom draw track BG',
423 'My Custom Draw Track BG Tooltip',
426 bg_color=[1.0, 0.3, 0.1, 0.5])
428 self.fg_draw_id = self.create_track_draw_object(
429 'custom draw track FG',
430 'My Custom Draw Track FG Tooltip',
433 bg_color=[0.0, 0.3, 0.1, 0.5])
435 manager.setStartPrimitiveEditFunction(self.fg_draw_id, self.startEdit)
436 manager.setEditPrimitiveFunction(self.fg_draw_id, self.editing)
437 manager.setSetCopyPrimitivesFunction(self.fg_draw_id, self.setCopying)
438 manager.setStopPrimitiveEditFunction(self.fg_draw_id, self.stopEdit)
440 self.fg_prims = [self.make_fg_obj_prims(self.fg_start)]
442 self.update_bg_primitives(manager, self.bg_draw_id)
443 self.update_fg_primitives(manager, self.fg_draw_id)
445 def update_bg_primitives(self, manager, bg_draw_id):
447 CustomSequencerDrawer.upper_outline_primitive(
448 15, 245, [0.2, 0.2, 0.8],
449 bottom=0.25
if self.toggled
else 0.0,
450 height=0.5
if self.toggled
else 1.0,
452 label=
'Track BG Upper Outline'
455 prims[-1].tooltip =
'BG Upper Outline Tooltip Text'
457 def make_menu(self, parent_id, time):
458 cmds.setParent(parent_id, menu=
True)
459 cmds.menuItem(label=
'Toggle Mode',
460 checkBox=self.toggled,
461 command=self.do_toggle)
463 prims[-1].setBuildMenuFunction(
464 lambda parent_id, time: make_menu(self, parent_id, time))
466 manager.setDrawPrimitives(bg_draw_id, prims)
468 def make_fg_obj_prims(self, start, label=None):
469 prim = CustomSequencerDrawer.full_outline_primitive(
470 start.asUnits(om.MTime.kFilm),
471 start.asUnits(om.MTime.kFilm) + self.fg_length,
472 [0.8, 0.8
if self.toggled
else 0.0, 0.2]
if self.edit_delta
is None else [1, 1, 1],
473 bottom=0.1, height=0.7, priority=2,
474 label=
'Drag to Move' if label
is None else label
476 prim.tooltip =
'Move by dragging or copy by Ctrl + dragging, right click for more options'
478 def make_menu(self, parent_id, time):
479 cmds.setParent(parent_id, menu=
True)
480 cmds.menuItem(label=
'Toggle Mode',
481 checkBox=self.toggled,
482 command=self.do_toggle)
483 cmds.menuItem(label=
'Duplicate',
484 command=
lambda *args: self.duplicate(prim))
485 cmds.menuItem(label=
'Delete',
486 command=
lambda *args: self.delete_at(time),
487 enable=len(self.fg_prims) > 1
and self.find_fg_prim_at_time(time)
is not None)
489 prim.setBuildMenuFunction(
490 lambda parent_id, time: make_menu(self, parent_id, time))
494 def update_fg_primitives(self, manager, fg_draw_id):
495 prims = self.fg_prims.copy()
497 if self.edit_delta
and self.fg_edit_prim:
498 self.fg_edit_prim.startTime = self.fg_start + self.edit_delta
499 self.fg_edit_prim.endTime = self.fg_start + om.MTime(self.fg_length) + self.edit_delta
501 if self.edit_copy
and self.edit_delta:
502 copy_prim = self.make_fg_obj_prims(self.fg_start,
'Ghost')
503 copy_prim.color = om.MColor([0.8, 0.8, 0.2, 0.5])
504 prims.append(copy_prim)
506 manager.setDrawPrimitives(fg_draw_id, prims)
508 def do_toggle(self, *args):
509 self.toggled =
not self.toggled
511 for prim
in self.fg_prims:
512 prim.color = om.MColor([0.8, 0.8
if self.toggled
else 0.0, 0.2])
514 self.update_bg_primitives(omui.MSequencerCustomDrawManager(), self.bg_draw_id)
515 self.update_fg_primitives(omui.MSequencerCustomDrawManager(), self.fg_draw_id)
517 def find_fg_prim_at_time(self, time):
518 for prim
in self.fg_prims:
519 if prim.startTime.asUnits(om.MTime.kFilm) <= time.asUnits(om.MTime.kFilm) <= prim.endTime.asUnits(om.MTime.kFilm):
523 def delete_at(self, time):
524 print(f
"Delete fg prim at time {time}")
525 found = self.find_fg_prim_at_time(time)
527 self.fg_prims.remove(found)
529 self.update_fg_primitives(omui.MSequencerCustomDrawManager(), self.fg_draw_id)
531 def duplicate(self, prim):
532 new_prim = self.make_fg_obj_prims(prim.startTime,
'Duplicate')
533 new_prim.startTime = prim.endTime + om.MTime(10)
534 new_prim.endTime = new_prim.startTime + om.MTime(self.fg_length)
535 self.fg_prims.append(new_prim)
536 self.update_fg_primitives(omui.MSequencerCustomDrawManager(), self.fg_draw_id)
538 def startEdit(self, time):
539 print(f
"Start editing track at time {time}")
540 self.fg_edit_prim = self.find_fg_prim_at_time(time)
541 self.fg_start = self.fg_edit_prim.startTime
if self.fg_edit_prim
else time
543 def editing(self, delta, currentTime):
544 print(f
"Editing track with delta {delta}, currentTime={currentTime}")
545 self.edit_delta = delta
546 self.update_fg_primitives(omui.MSequencerCustomDrawManager(), self.fg_draw_id)
549 print(
"Stop editing track")
550 if self.edit_delta
and self.fg_edit_prim:
551 self.fg_edit_prim.startTime = self.fg_start + self.edit_delta
552 self.fg_edit_prim.endTime = self.fg_start + om.MTime(self.fg_length) + self.edit_delta
555 self.fg_prims.insert(0, self.make_fg_obj_prims(self.fg_start,
'Copied'))
557 self.edit_delta =
None
558 self.edit_copy =
False
559 self.fg_edit_prim =
None
560 self.update_fg_primitives(omui.MSequencerCustomDrawManager(), self.fg_draw_id)
562 def setCopying(self, copying):
563 print(f
"Set copying to {copying} for track")
564 self.edit_copy = copying
567 class AudioTrackDrawDemo(CustomSequencerDrawer):
569 Demo custom drawing in the Sequencer for an audio track.
570 Includes both track and track title custom draw objects.
573 self.track_draw_id = 0
574 self.title_draw_id = 0
575 self.track_number = 2
577 self.toggled_title =
False
580 def init_draw_objects(self):
581 manager = omui.MSequencerCustomDrawManager()
582 self.create_audio_track_draw_object(manager)
583 self.create_audio_title_draw_object(manager)
585 def create_audio_track_draw_object(self, manager):
586 self.track_draw_id = self.create_track_draw_object(
587 'custom draw audio track',
588 'Audio Track Tooltip',
590 trackNumber=self.track_number,
592 bg_color=[0.1, 0.8, 0.2, 0.7]
595 manager.setStartPrimitiveEditFunction(self.track_draw_id, self.startEdit)
596 manager.setEditPrimitiveFunction(self.track_draw_id, self.editing)
597 manager.setSetCopyPrimitivesFunction(self.track_draw_id, self.setCopying)
598 manager.setStopPrimitiveEditFunction(self.track_draw_id, self.stopEdit)
600 self.update_track_primitives(manager)
602 def create_audio_title_draw_object(self, manager):
603 self.title_draw_id = self.create_track_title_draw_object(
604 'custom draw audio track title',
605 'Audio Track Title Tooltip',
607 trackNumber=self.track_number,
609 bg_color=[0.8, 0.1, 0.2]
612 self.update_title_primitives(manager)
614 def update_track_primitives(self, manager):
616 CustomSequencerDrawer.filled_rect_primitive(
617 100, 300
if self.toggled
else 150, [0.2, 0.2, 0.2, 0.75],
618 bottom=0.2, height=0.7, priority=1
621 prims[-1].tooltip =
'Audio Track Filled Rect Tooltip Text'
623 def sample_menu_item(self, *args):
624 self.toggled =
not self.toggled
625 self.update_track_primitives(manager)
627 def make_menu(self, parent_id, time):
628 cmds.setParent(parent_id, menu=
True)
629 cmds.menuItem(label=f
'Example Audio Menu Item {time}',
630 command=
lambda *args: sample_menu_item(self, *args))
632 prims[-1].setBuildMenuFunction(
633 lambda parent_id, time: make_menu(self, parent_id, time))
635 manager.setDrawPrimitives(self.track_draw_id, prims)
637 def update_title_primitives(self, manager):
639 CustomSequencerDrawer.text_primitive(
641 bottom=0.1, height=0.8, priority=1,
642 label=
'Audio Track Title Object'
644 CustomSequencerDrawer.filled_rect_primitive(
645 10, 85, [0.2, 0.2, 0.2, 0.75],
646 bottom=0.5
if self.toggled_title
else 0.0,
647 height=0.4
if self.toggled_title
else 1.0,
651 prims[-1].tooltip =
'Audio Track Title Text Tooltip Text'
653 def sample_menu_item(self, *args):
654 self.toggled_title =
not self.toggled_title
655 self.update_title_primitives(manager)
657 def make_menu(self, parent_id, time):
658 cmds.setParent(parent_id, menu=
True)
659 cmds.menuItem(label=f
'Example Audio Title Menu Item {time}',
660 command=
lambda *args: sample_menu_item(self, *args))
662 prims[-1].setBuildMenuFunction(
663 lambda parent_id, time: make_menu(self, parent_id, time))
665 manager.setDrawPrimitives(self.title_draw_id, prims)
667 def startEdit(self, time):
668 print(f
"Start editing audio track obj at time {time}")
670 def editing(self, time, currentTime):
671 print(f
"Editing audio track obj at time {time}, currentTime={currentTime}")
674 print(
"Stop editing audio track obj")
676 def setCopying(self, copying):
677 print(f
"Set copying to {copying} for audio track obj")
680 def _setup_demo_sequencer_draw_manager():
681 global custom_sequencer_drawers
683 print(
"Demo sequencer draw manager")
685 if custom_sequencer_drawers:
686 for drawer
in custom_sequencer_drawers:
689 custom_sequencer_drawers = [
690 SequencerTimelineDrawDemo(),
691 ShotTrackTitleDrawDemo(),
693 AudioTrackDrawDemo(),
696 _setup_exit_callback()
699 def _setup_exit_callback():
700 global maya_exit_callback_id
702 if maya_exit_callback_id
is not None:
705 maya_exit_callback_id = om.MSceneMessage.addCallback(
706 om.MSceneMessage.kMayaExiting,
711 def _cleanup_custom_sequencer_drawers():
712 global custom_sequencer_drawers
714 if not custom_sequencer_drawers:
717 for drawer
in custom_sequencer_drawers:
720 custom_sequencer_drawers =
None
723 def _remove_exit_callback():
724 global maya_exit_callback_id
726 if maya_exit_callback_id
is None:
730 om.MMessage.removeCallback(maya_exit_callback_id)
735 maya_exit_callback_id =
None
738 def _on_maya_exiting(*args):
739 _cleanup_custom_sequencer_drawers()
740 _remove_exit_callback()
743 def initializePlugin(mobject):
744 _setup_exit_callback()
745 _setup_demo_sequencer_draw_manager()
748 def uninitializePlugin(mobject):
749 global custom_sequencer_drawers
751 print(
"Uninitialize plugin and clear custom sequencer drawers")
753 _cleanup_custom_sequencer_drawers()
754 _remove_exit_callback()
757 def maya_useNewAPI():
761 if __name__ ==
'__main__':
762 _setup_demo_sequencer_draw_manager()