2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <pbd/stacktrace.h>
26 #include <ardour/audio_diskstream.h>
27 #include <ardour/audioplaylist.h>
31 #include "public_editor.h"
32 #include "audio_region_view.h"
33 #include "audio_streamview.h"
34 #include "crossfade_view.h"
35 #include "audio_time_axis.h"
36 #include "region_gain_line.h"
37 #include "automation_gain_line.h"
38 #include "automation_pan_line.h"
39 #include "automation_time_axis.h"
40 #include "redirect_automation_line.h"
41 #include "canvas_impl.h"
42 #include "simplerect.h"
48 using namespace ARDOUR
;
53 Editor::track_canvas_scroll (GdkEventScroll
* ev
)
58 int direction
= ev
->direction
;
63 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
64 //if (ev->state == GDK_CONTROL_MASK) {
66 the ev->x will be out of step with the canvas
67 if we're in mid zoom, so we have to get the damn mouse
70 track_canvas
->get_pointer (x
, y
);
71 track_canvas
->window_to_world (x
, y
, wx
, wy
);
74 event
.type
= GDK_BUTTON_RELEASE
;
78 nframes64_t where
= event_frame (&event
, 0, 0);
79 temporal_zoom_to_frame (false, where
);
81 } else if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::SecondaryModifier
)) {
82 direction
= GDK_SCROLL_LEFT
;
84 } else if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::TertiaryModifier
)) {
85 if (!current_stepping_trackview
) {
86 step_timeout
= Glib::signal_timeout().connect (mem_fun(*this, &Editor::track_height_step_timeout
), 500);
87 if (!(current_stepping_trackview
= trackview_by_y_position (ev
->y
+ vertical_adjustment
.get_value() - canvas_timebars_vsize
))) {
91 last_track_height_step_timestamp
= get_microseconds();
92 current_stepping_trackview
->step_height (true);
95 scroll_tracks_up_line ();
100 case GDK_SCROLL_DOWN
:
101 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
102 //if (ev->state == GDK_CONTROL_MASK) {
103 track_canvas
->get_pointer (x
, y
);
104 track_canvas
->window_to_world (x
, y
, wx
, wy
);
107 event
.type
= GDK_BUTTON_RELEASE
;
111 nframes64_t where
= event_frame (&event
, 0, 0);
112 temporal_zoom_to_frame (true, where
);
114 } else if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::SecondaryModifier
)) {
115 direction
= GDK_SCROLL_RIGHT
;
117 } else if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::TertiaryModifier
)) {
118 if (!current_stepping_trackview
) {
119 step_timeout
= Glib::signal_timeout().connect (mem_fun(*this, &Editor::track_height_step_timeout
), 500);
120 if (!(current_stepping_trackview
= trackview_by_y_position (ev
->y
+ vertical_adjustment
.get_value() - canvas_timebars_vsize
))) {
124 last_track_height_step_timestamp
= get_microseconds();
125 current_stepping_trackview
->step_height (false);
128 scroll_tracks_down_line ();
133 case GDK_SCROLL_LEFT
:
134 xdelta
= (current_page_frames() / 8);
135 if (leftmost_frame
> xdelta
) {
136 reset_x_origin (leftmost_frame
- xdelta
);
142 case GDK_SCROLL_RIGHT
:
143 xdelta
= (current_page_frames() / 8);
144 if (max_frames
- xdelta
> leftmost_frame
) {
145 reset_x_origin (leftmost_frame
+ xdelta
);
147 reset_x_origin (max_frames
- current_page_frames());
160 Editor::track_canvas_scroll_event (GdkEventScroll
*event
)
162 track_canvas
->grab_focus();
163 track_canvas_scroll (event
);
168 Editor::track_canvas_button_press_event (GdkEventButton
*event
)
171 track_canvas
->grab_focus();
176 Editor::track_canvas_button_release_event (GdkEventButton
*event
)
178 if (drag_info
.item
) {
179 end_grab (drag_info
.item
, (GdkEvent
*) event
);
185 Editor::track_canvas_motion_notify_event (GdkEventMotion
*event
)
188 /* keep those motion events coming */
189 track_canvas
->get_pointer (x
, y
);
194 Editor::track_canvas_motion (GdkEvent
*ev
)
196 if (verbose_cursor_visible
) {
197 verbose_canvas_cursor
->property_x() = clamp_verbose_cursor_x (ev
->motion
.x
+ 10);
198 verbose_canvas_cursor
->property_y() = clamp_verbose_cursor_y (ev
->motion
.y
+ 10);
205 Editor::typed_event (ArdourCanvas::Item
* item
, GdkEvent
*event
, ItemType type
)
209 switch (event
->type
) {
210 case GDK_BUTTON_PRESS
:
211 case GDK_2BUTTON_PRESS
:
212 case GDK_3BUTTON_PRESS
:
213 ret
= button_press_handler (item
, event
, type
);
215 case GDK_BUTTON_RELEASE
:
216 ret
= button_release_handler (item
, event
, type
);
218 case GDK_MOTION_NOTIFY
:
219 ret
= motion_handler (item
, event
, type
);
222 case GDK_ENTER_NOTIFY
:
223 ret
= enter_handler (item
, event
, type
);
226 case GDK_LEAVE_NOTIFY
:
227 ret
= leave_handler (item
, event
, type
);
237 Editor::canvas_region_view_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, RegionView
*rv
)
241 if (!rv
->sensitive ()) {
246 switch (event
->type
) {
247 case GDK_BUTTON_PRESS
:
248 case GDK_2BUTTON_PRESS
:
249 case GDK_3BUTTON_PRESS
:
250 clicked_regionview
= rv
;
251 clicked_control_point
= 0;
252 clicked_trackview
= &rv
->get_time_axis_view();
253 clicked_audio_trackview
= dynamic_cast<AudioTimeAxisView
*>(clicked_trackview
);
254 ret
= button_press_handler (item
, event
, RegionItem
);
257 case GDK_BUTTON_RELEASE
:
258 ret
= button_release_handler (item
, event
, RegionItem
);
261 case GDK_MOTION_NOTIFY
:
262 ret
= motion_handler (item
, event
, RegionItem
);
265 case GDK_ENTER_NOTIFY
:
266 set_entered_track (&rv
->get_time_axis_view ());
267 set_entered_regionview (rv
);
270 case GDK_LEAVE_NOTIFY
:
271 set_entered_track (0);
272 set_entered_regionview (0);
283 Editor::canvas_stream_view_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, RouteTimeAxisView
*tv
)
287 switch (event
->type
) {
288 case GDK_BUTTON_PRESS
:
289 case GDK_2BUTTON_PRESS
:
290 case GDK_3BUTTON_PRESS
:
291 clicked_regionview
= 0;
292 clicked_control_point
= 0;
293 clicked_trackview
= tv
;
294 clicked_audio_trackview
= dynamic_cast<AudioTimeAxisView
*>(tv
);
295 ret
= button_press_handler (item
, event
, StreamItem
);
298 case GDK_BUTTON_RELEASE
:
299 ret
= button_release_handler (item
, event
, StreamItem
);
302 case GDK_MOTION_NOTIFY
:
303 ret
= motion_handler (item
, event
, StreamItem
);
306 case GDK_ENTER_NOTIFY
:
307 set_entered_track (tv
);
310 case GDK_LEAVE_NOTIFY
:
311 set_entered_track (0);
322 Editor::canvas_automation_track_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, AutomationTimeAxisView
*atv
)
327 switch (event
->type
) {
328 case GDK_BUTTON_PRESS
:
329 case GDK_2BUTTON_PRESS
:
330 case GDK_3BUTTON_PRESS
:
331 clicked_regionview
= 0;
332 clicked_control_point
= 0;
333 clicked_trackview
= atv
;
334 clicked_audio_trackview
= 0;
335 ret
= button_press_handler (item
, event
, AutomationTrackItem
);
338 case GDK_BUTTON_RELEASE
:
339 ret
= button_release_handler (item
, event
, AutomationTrackItem
);
342 case GDK_MOTION_NOTIFY
:
343 ret
= motion_handler (item
, event
, AutomationTrackItem
);
346 case GDK_ENTER_NOTIFY
:
347 ret
= enter_handler (item
, event
, AutomationTrackItem
);
350 case GDK_LEAVE_NOTIFY
:
351 ret
= leave_handler (item
, event
, AutomationTrackItem
);
362 Editor::canvas_fade_in_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, AudioRegionView
*rv
)
364 /* we handle only button 3 press/release events */
366 if (!rv
->sensitive()) {
370 switch (event
->type
) {
371 case GDK_BUTTON_PRESS
:
372 clicked_regionview
= rv
;
373 clicked_control_point
= 0;
374 clicked_trackview
= &rv
->get_time_axis_view();
375 clicked_audio_trackview
= dynamic_cast<AudioTimeAxisView
*>(clicked_trackview
);
376 if (event
->button
.button
== 3) {
377 return button_press_handler (item
, event
, FadeInItem
);
381 case GDK_BUTTON_RELEASE
:
382 if (event
->button
.button
== 3) {
383 return button_release_handler (item
, event
, FadeInItem
);
392 /* proxy for the regionview */
394 return canvas_region_view_event (event
, rv
->get_canvas_group(), rv
);
398 Editor::canvas_fade_in_handle_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, AudioRegionView
*rv
)
402 if (!rv
->sensitive()) {
406 switch (event
->type
) {
407 case GDK_BUTTON_PRESS
:
408 case GDK_2BUTTON_PRESS
:
409 case GDK_3BUTTON_PRESS
:
410 clicked_regionview
= rv
;
411 clicked_control_point
= 0;
412 clicked_trackview
= &rv
->get_time_axis_view();
413 clicked_audio_trackview
= dynamic_cast<AudioTimeAxisView
*>(clicked_trackview
);
414 ret
= button_press_handler (item
, event
, FadeInHandleItem
);
417 case GDK_BUTTON_RELEASE
:
418 ret
= button_release_handler (item
, event
, FadeInHandleItem
);
421 case GDK_MOTION_NOTIFY
:
422 ret
= motion_handler (item
, event
, FadeInHandleItem
);
425 case GDK_ENTER_NOTIFY
:
426 ret
= enter_handler (item
, event
, FadeInHandleItem
);
429 case GDK_LEAVE_NOTIFY
:
430 ret
= leave_handler (item
, event
, FadeInHandleItem
);
441 Editor::canvas_fade_out_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, AudioRegionView
*rv
)
443 /* we handle only button 3 press/release events */
445 if (!rv
->sensitive()) {
449 switch (event
->type
) {
450 case GDK_BUTTON_PRESS
:
451 clicked_regionview
= rv
;
452 clicked_control_point
= 0;
453 clicked_trackview
= &rv
->get_time_axis_view();
454 clicked_audio_trackview
= dynamic_cast<AudioTimeAxisView
*>(clicked_trackview
);
455 if (event
->button
.button
== 3) {
456 return button_press_handler (item
, event
, FadeOutItem
);
460 case GDK_BUTTON_RELEASE
:
461 if (event
->button
.button
== 3) {
462 return button_release_handler (item
, event
, FadeOutItem
);
471 /* proxy for the regionview */
473 return canvas_region_view_event (event
, rv
->get_canvas_group(), rv
);
477 Editor::canvas_fade_out_handle_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, AudioRegionView
*rv
)
481 if (!rv
->sensitive()) {
485 switch (event
->type
) {
486 case GDK_BUTTON_PRESS
:
487 case GDK_2BUTTON_PRESS
:
488 case GDK_3BUTTON_PRESS
:
489 clicked_regionview
= rv
;
490 clicked_control_point
= 0;
491 clicked_trackview
= &rv
->get_time_axis_view();
492 clicked_audio_trackview
= dynamic_cast<AudioTimeAxisView
*>(clicked_trackview
);
493 ret
= button_press_handler (item
, event
, FadeOutHandleItem
);
496 case GDK_BUTTON_RELEASE
:
497 ret
= button_release_handler (item
, event
, FadeOutHandleItem
);
500 case GDK_MOTION_NOTIFY
:
501 ret
= motion_handler (item
, event
, FadeOutHandleItem
);
504 case GDK_ENTER_NOTIFY
:
505 ret
= enter_handler (item
, event
, FadeOutHandleItem
);
508 case GDK_LEAVE_NOTIFY
:
509 ret
= leave_handler (item
, event
, FadeOutHandleItem
);
519 struct DescendingRegionLayerSorter
{
520 bool operator()(boost::shared_ptr
<Region
> a
, boost::shared_ptr
<Region
> b
) {
521 return a
->layer() > b
->layer();
526 Editor::canvas_crossfade_view_event (GdkEvent
* event
, ArdourCanvas::Item
* item
, CrossfadeView
* xfv
)
528 /* we handle only button 3 press/release events */
530 switch (event
->type
) {
531 case GDK_BUTTON_PRESS
:
532 clicked_crossfadeview
= xfv
;
533 clicked_trackview
= &clicked_crossfadeview
->get_time_axis_view();
534 if (event
->button
.button
== 3) {
535 return button_press_handler (item
, event
, CrossfadeViewItem
);
539 case GDK_BUTTON_RELEASE
:
540 if (event
->button
.button
== 3) {
541 bool ret
= button_release_handler (item
, event
, CrossfadeViewItem
);
551 /* XXX do not forward double clicks */
553 if (event
->type
== GDK_2BUTTON_PRESS
) {
557 /* proxy for the upper most regionview */
559 /* XXX really need to check if we are in the name highlight,
560 and proxy to that when required.
563 TimeAxisView
& tv (xfv
->get_time_axis_view());
564 AudioTimeAxisView
* atv
;
566 if ((atv
= dynamic_cast<AudioTimeAxisView
*>(&tv
)) != 0) {
568 if (atv
->is_audio_track()) {
570 boost::shared_ptr
<AudioPlaylist
> pl
;
571 if ((pl
= boost::dynamic_pointer_cast
<AudioPlaylist
> (atv
->get_diskstream()->playlist())) != 0) {
573 Playlist::RegionList
* rl
= pl
->regions_at (event_frame (event
));
576 DescendingRegionLayerSorter cmp
;
579 RegionView
* rv
= atv
->view()->find_view (rl
->front());
585 return canvas_region_view_event (event
, rv
->get_canvas_group(), rv
);
597 Editor::canvas_control_point_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, ControlPoint
* cp
)
601 switch (event
->type
) {
602 case GDK_BUTTON_PRESS
:
603 case GDK_2BUTTON_PRESS
:
604 case GDK_3BUTTON_PRESS
:
605 clicked_control_point
= cp
;
606 clicked_trackview
= &cp
->line
.trackview
;
607 clicked_audio_trackview
= dynamic_cast<AudioTimeAxisView
*>(clicked_trackview
);
608 clicked_regionview
= 0;
614 case GDK_SCROLL_DOWN
:
621 if (dynamic_cast<AudioRegionGainLine
*> (&cp
->line
) != 0) {
622 type
= GainControlPointItem
;
623 } else if (dynamic_cast<AutomationGainLine
*> (&cp
->line
) != 0) {
624 type
= GainAutomationControlPointItem
;
625 } else if (dynamic_cast<AutomationPanLine
*> (&cp
->line
) != 0) {
626 type
= PanAutomationControlPointItem
;
627 } else if (dynamic_cast<RedirectAutomationLine
*> (&cp
->line
) != 0) {
628 type
= RedirectAutomationControlPointItem
;
633 return typed_event (item
, event
, type
);
637 Editor::canvas_line_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, AutomationLine
* al
)
641 if (dynamic_cast<AudioRegionGainLine
*> (al
) != 0) {
643 } else if (dynamic_cast<AutomationGainLine
*> (al
) != 0) {
644 type
= GainAutomationLineItem
;
645 } else if (dynamic_cast<AutomationPanLine
*> (al
) != 0) {
646 type
= PanAutomationLineItem
;
647 } else if (dynamic_cast<RedirectAutomationLine
*> (al
) != 0) {
648 type
= RedirectAutomationLineItem
;
653 return typed_event (item
, event
, type
);
657 Editor::canvas_selection_rect_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, SelectionRect
* rect
)
661 switch (event
->type
) {
662 case GDK_BUTTON_PRESS
:
663 case GDK_2BUTTON_PRESS
:
664 case GDK_3BUTTON_PRESS
:
665 clicked_selection
= rect
->id
;
666 ret
= button_press_handler (item
, event
, SelectionItem
);
668 case GDK_BUTTON_RELEASE
:
669 ret
= button_release_handler (item
, event
, SelectionItem
);
671 case GDK_MOTION_NOTIFY
:
672 ret
= motion_handler (item
, event
, SelectionItem
);
674 /* Don't need these at the moment. */
675 case GDK_ENTER_NOTIFY
:
676 ret
= enter_handler (item
, event
, SelectionItem
);
679 case GDK_LEAVE_NOTIFY
:
680 ret
= leave_handler (item
, event
, SelectionItem
);
691 Editor::canvas_selection_start_trim_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, SelectionRect
* rect
)
695 switch (event
->type
) {
696 case GDK_BUTTON_PRESS
:
697 case GDK_2BUTTON_PRESS
:
698 case GDK_3BUTTON_PRESS
:
699 clicked_selection
= rect
->id
;
700 ret
= button_press_handler (item
, event
, StartSelectionTrimItem
);
702 case GDK_BUTTON_RELEASE
:
703 ret
= button_release_handler (item
, event
, StartSelectionTrimItem
);
705 case GDK_MOTION_NOTIFY
:
706 ret
= motion_handler (item
, event
, StartSelectionTrimItem
);
708 case GDK_ENTER_NOTIFY
:
709 ret
= enter_handler (item
, event
, StartSelectionTrimItem
);
712 case GDK_LEAVE_NOTIFY
:
713 ret
= leave_handler (item
, event
, StartSelectionTrimItem
);
724 Editor::canvas_selection_end_trim_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, SelectionRect
* rect
)
728 switch (event
->type
) {
729 case GDK_BUTTON_PRESS
:
730 case GDK_2BUTTON_PRESS
:
731 case GDK_3BUTTON_PRESS
:
732 clicked_selection
= rect
->id
;
733 ret
= button_press_handler (item
, event
, EndSelectionTrimItem
);
735 case GDK_BUTTON_RELEASE
:
736 ret
= button_release_handler (item
, event
, EndSelectionTrimItem
);
738 case GDK_MOTION_NOTIFY
:
739 ret
= motion_handler (item
, event
, EndSelectionTrimItem
);
741 case GDK_ENTER_NOTIFY
:
742 ret
= enter_handler (item
, event
, EndSelectionTrimItem
);
745 case GDK_LEAVE_NOTIFY
:
746 ret
= leave_handler (item
, event
, EndSelectionTrimItem
);
758 Editor::canvas_region_view_name_highlight_event (GdkEvent
* event
, ArdourCanvas::Item
* item
, RegionView
* rv
)
762 if (!rv
->sensitive()) {
766 switch (event
->type
) {
767 case GDK_BUTTON_PRESS
:
768 case GDK_2BUTTON_PRESS
:
769 case GDK_3BUTTON_PRESS
:
770 clicked_regionview
= rv
;
771 clicked_control_point
= 0;
772 clicked_trackview
= &clicked_regionview
->get_time_axis_view();
773 clicked_audio_trackview
= dynamic_cast<AudioTimeAxisView
*>(clicked_trackview
);
774 ret
= button_press_handler (item
, event
, RegionViewNameHighlight
);
776 case GDK_BUTTON_RELEASE
:
777 ret
= button_release_handler (item
, event
, RegionViewNameHighlight
);
779 case GDK_MOTION_NOTIFY
:
780 ret
= motion_handler (item
, event
, RegionViewNameHighlight
);
782 case GDK_ENTER_NOTIFY
:
783 ret
= enter_handler (item
, event
, RegionViewNameHighlight
);
786 case GDK_LEAVE_NOTIFY
:
787 ret
= leave_handler (item
, event
, RegionViewNameHighlight
);
798 Editor::canvas_region_view_name_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, RegionView
* rv
)
802 if (!rv
->sensitive()) {
806 switch (event
->type
) {
807 case GDK_BUTTON_PRESS
:
808 case GDK_2BUTTON_PRESS
:
809 case GDK_3BUTTON_PRESS
:
810 clicked_regionview
= rv
;
811 clicked_control_point
= 0;
812 clicked_trackview
= &clicked_regionview
->get_time_axis_view();
813 clicked_audio_trackview
= dynamic_cast<AudioTimeAxisView
*>(clicked_trackview
);
814 ret
= button_press_handler (item
, event
, RegionViewName
);
816 case GDK_BUTTON_RELEASE
:
817 ret
= button_release_handler (item
, event
, RegionViewName
);
819 case GDK_MOTION_NOTIFY
:
820 ret
= motion_handler (item
, event
, RegionViewName
);
822 case GDK_ENTER_NOTIFY
:
823 ret
= enter_handler (item
, event
, RegionViewName
);
826 case GDK_LEAVE_NOTIFY
:
827 ret
= leave_handler (item
, event
, RegionViewName
);
838 Editor::canvas_marker_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, Marker
* marker
)
840 return typed_event (item
, event
, MarkerItem
);
844 Editor::canvas_marker_bar_event (GdkEvent
*event
, ArdourCanvas::Item
* item
)
846 return typed_event (item
, event
, MarkerBarItem
);
850 Editor::canvas_range_marker_bar_event (GdkEvent
*event
, ArdourCanvas::Item
* item
)
852 return typed_event (item
, event
, RangeMarkerBarItem
);
856 Editor::canvas_transport_marker_bar_event (GdkEvent
*event
, ArdourCanvas::Item
* item
)
858 return typed_event (item
, event
, TransportMarkerBarItem
);
862 Editor::canvas_cd_marker_bar_event (GdkEvent
*event
, ArdourCanvas::Item
* item
)
864 return typed_event (item
, event
, CdMarkerBarItem
);
868 Editor::canvas_tempo_marker_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, TempoMarker
* marker
)
870 return typed_event (item
, event
, TempoMarkerItem
);
874 Editor::canvas_meter_marker_event (GdkEvent
*event
, ArdourCanvas::Item
* item
, MeterMarker
* marker
)
876 return typed_event (item
, event
, MeterMarkerItem
);
880 Editor::canvas_tempo_bar_event (GdkEvent
*event
, ArdourCanvas::Item
* item
)
882 return typed_event (item
, event
, TempoBarItem
);
886 Editor::canvas_meter_bar_event (GdkEvent
*event
, ArdourCanvas::Item
* item
)
888 return typed_event (item
, event
, MeterBarItem
);
892 Editor::canvas_playhead_cursor_event (GdkEvent
*event
, ArdourCanvas::Item
* item
)
894 return typed_event (item
, event
, PlayheadCursorItem
);
898 Editor::canvas_zoom_rect_event (GdkEvent
*event
, ArdourCanvas::Item
* item
)
900 return typed_event (item
, event
, NoItem
);