sort export formats & presets in alphabetical name order
[ardour.git] / gtk2_ardour / time_axis_view_item.cc
1 /*
2     Copyright (C) 2003 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #include "pbd/error.h"
21 #include "pbd/stacktrace.h"
22
23 #include "ardour/types.h"
24 #include "ardour/ardour.h"
25
26 #include "gtkmm2ext/utils.h"
27 #include "gtkmm2ext/gui_thread.h"
28
29 #include "ardour_ui.h"
30 /*
31  * ardour_ui.h was moved up in the include list
32  * due to a conflicting definition of 'Rect' between
33  * Apple's MacTypes.h file and GTK
34  */
35
36 #include "public_editor.h"
37 #include "time_axis_view_item.h"
38 #include "time_axis_view.h"
39 #include "simplerect.h"
40 #include "utils.h"
41 #include "canvas_impl.h"
42 #include "rgb_macros.h"
43
44 #include "i18n.h"
45
46 using namespace std;
47 using namespace Editing;
48 using namespace Glib;
49 using namespace PBD;
50 using namespace ARDOUR;
51 using namespace Gtkmm2ext;
52
53 Pango::FontDescription* TimeAxisViewItem::NAME_FONT = 0;
54 const double TimeAxisViewItem::NAME_X_OFFSET = 15.0;
55 const double TimeAxisViewItem::GRAB_HANDLE_LENGTH = 6;
56
57 int    TimeAxisViewItem::NAME_HEIGHT;
58 double TimeAxisViewItem::NAME_Y_OFFSET;
59 double TimeAxisViewItem::NAME_HIGHLIGHT_SIZE;
60 double TimeAxisViewItem::NAME_HIGHLIGHT_THRESH;
61
62 void
63 TimeAxisViewItem::set_constant_heights ()
64 {
65         NAME_FONT = get_font_for_style (X_("TimeAxisViewItemName"));
66         
67         Gtk::Window win;
68         Gtk::Label foo;
69         win.add (foo);
70         
71         Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout (X_("Hg")); /* ascender + descender */
72         int width = 0;
73         int height = 0;
74         
75         layout->set_font_description (*NAME_FONT);
76         Gtkmm2ext::get_ink_pixel_size (layout, width, height);
77         
78         NAME_HEIGHT = height;
79         NAME_Y_OFFSET = height + 3;
80         NAME_HIGHLIGHT_SIZE = height + 2;
81         NAME_HIGHLIGHT_THRESH = NAME_HIGHLIGHT_SIZE * 3;
82 }
83
84 /**
85  * Construct a new TimeAxisViewItem.
86  *
87  * @param it_name the unique name of this item
88  * @param parent the parent canvas group
89  * @param tv the TimeAxisView we are going to be added to
90  * @param spu samples per unit
91  * @param base_color
92  * @param start the start point of this item
93  * @param duration the duration of this item
94  * @param recording true if this is a recording region view
95  * @param automation true if this is an automation region view
96  */
97 TimeAxisViewItem::TimeAxisViewItem(
98         const string & it_name, ArdourCanvas::Group& parent, TimeAxisView& tv, double spu, Gdk::Color const & base_color,
99         framepos_t start, framecnt_t duration, bool recording, bool automation, Visibility vis
100         )
101         : trackview (tv)
102         , _height (1.0)
103         , _recregion (recording)
104         , _automation (automation)
105 {
106         group = new ArdourCanvas::Group (parent);
107
108         init (it_name, spu, base_color, start, duration, vis, true, true);
109 }
110
111 TimeAxisViewItem::TimeAxisViewItem (const TimeAxisViewItem& other)
112         : sigc::trackable(other)
113         , PBD::ScopedConnectionList()
114         , trackview (other.trackview)
115         , _recregion (other._recregion)
116         , _automation (other._automation)
117 {
118
119         Gdk::Color c;
120         int r,g,b,a;
121
122         UINT_TO_RGBA (other.fill_color, &r, &g, &b, &a);
123         c.set_rgb_p (r/255.0, g/255.0, b/255.0);
124
125         /* share the other's parent, but still create a new group */
126
127         Gnome::Canvas::Group* parent = other.group->property_parent();
128
129         group = new ArdourCanvas::Group (*parent);
130
131         _selected = other._selected;
132
133         init (
134                 other.item_name, other.samples_per_unit, c, other.frame_position,
135                 other.item_duration, other.visibility, other.wide_enough_for_name, other.high_enough_for_name
136                 );
137 }
138
139 void
140 TimeAxisViewItem::init (
141         const string& it_name, double spu, Gdk::Color const & base_color, framepos_t start, framepos_t duration, Visibility vis, bool wide, bool high)
142 {
143         item_name = it_name;
144         samples_per_unit = spu;
145         frame_position = start;
146         item_duration = duration;
147         name_connected = false;
148         fill_opacity = 60;
149         position_locked = false;
150         max_item_duration = ARDOUR::max_framepos;
151         min_item_duration = 0;
152         show_vestigial = true;
153         visibility = vis;
154         _sensitive = true;
155         name_pixbuf_width = 0;
156         last_item_width = 0;
157         wide_enough_for_name = wide;
158         high_enough_for_name = high;
159         rect_visible = true;
160
161         if (duration == 0) {
162                 warning << "Time Axis Item Duration == 0" << endl;
163         }
164
165         vestigial_frame = new ArdourCanvas::SimpleRect (*group, 0.0, 1.0, 2.0, trackview.current_height());
166         vestigial_frame->hide ();
167         vestigial_frame->property_outline_what() = 0xF;
168         vestigial_frame->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_VestigialFrame.get();
169         vestigial_frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_VestigialFrame.get();
170
171         if (visibility & ShowFrame) {
172                 frame = new ArdourCanvas::SimpleRect (*group, 0.0, 1.0, trackview.editor().frame_to_pixel(duration), trackview.current_height());
173                 
174                 frame->property_outline_pixels() = 1;
175                 frame->property_outline_what() = 0xF;
176                 
177                 if (_recregion) {
178                         frame->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RecordingRect.get();
179                 } else {
180                         frame->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeAxisFrame.get();
181                 }
182                 
183                 frame->property_outline_what() = 0x1|0x2|0x4|0x8;
184
185         } else {
186                 frame = 0;
187         }
188
189         if (visibility & ShowNameHighlight) {
190                 
191                 if (visibility & FullWidthNameHighlight) {
192                         name_highlight = new ArdourCanvas::SimpleRect (*group, 0.0, trackview.editor().frame_to_pixel(item_duration), trackview.current_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE, trackview.current_height());
193                 } else {
194                         name_highlight = new ArdourCanvas::SimpleRect (*group, 1.0, trackview.editor().frame_to_pixel(item_duration) - 1, trackview.current_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE, trackview.current_height());
195                 }
196                 
197                 name_highlight->set_data ("timeaxisviewitem", this);
198                 name_highlight->property_outline_what() = 0x4;
199                 /* we should really use a canvas color property here */
200                 name_highlight->property_outline_color_rgba() = RGBA_TO_UINT (0,0,0,255);
201
202         } else {
203                 name_highlight = 0;
204         }
205
206         if (visibility & ShowNameText) {
207                 name_pixbuf = new ArdourCanvas::Pixbuf(*group);
208                 name_pixbuf->property_x() = NAME_X_OFFSET;
209                 name_pixbuf->property_y() = trackview.current_height() + 1 - NAME_Y_OFFSET;
210
211         } else {
212                 name_pixbuf = 0;
213         }
214
215         /* create our grab handles used for trimming/duration etc */
216         if (!_recregion && !_automation) {
217                 frame_handle_start = new ArdourCanvas::SimpleRect (*group, 0.0, TimeAxisViewItem::GRAB_HANDLE_LENGTH, 5.0, trackview.current_height());
218                 frame_handle_start->property_outline_what() = 0x0;
219                 frame_handle_end = new ArdourCanvas::SimpleRect (*group, 0.0, TimeAxisViewItem::GRAB_HANDLE_LENGTH, 5.0, trackview.current_height());
220                 frame_handle_end->property_outline_what() = 0x0;
221         } else {
222                 frame_handle_start = frame_handle_end = 0;
223         }
224
225         set_color (base_color);
226
227         set_duration (item_duration, this);
228         set_position (start, this);
229
230         Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&TimeAxisViewItem::parameter_changed, this, _1), gui_context ());
231 }
232
233 TimeAxisViewItem::~TimeAxisViewItem()
234 {
235         delete group;
236 }
237
238 void
239 TimeAxisViewItem::hide_rect ()
240 {
241         rect_visible = false;
242         set_frame_color ();
243
244         if (name_highlight) {
245                 name_highlight->property_outline_what() = 0x0;
246                 name_highlight->property_fill_color_rgba() = UINT_RGBA_CHANGE_A(fill_color,64);
247         }
248 }
249
250 void
251 TimeAxisViewItem::show_rect ()
252 {
253         rect_visible = true;
254         set_frame_color ();
255
256         if (name_highlight) {
257                 name_highlight->property_outline_what() = 0x4;
258                 name_highlight->property_fill_color_rgba() = fill_color;
259         }
260 }
261
262
263 /**
264  * Set the position of this item on the timeline.
265  *
266  * @param pos the new position
267  * @param src the identity of the object that initiated the change
268  * @return true on success
269  */
270
271 bool
272 TimeAxisViewItem::set_position(framepos_t pos, void* src, double* delta)
273 {
274         if (position_locked) {
275                 return false;
276         }
277
278         frame_position = pos;
279
280         /*  This sucks. The GnomeCanvas version I am using
281             doesn't correctly implement gnome_canvas_group_set_arg(),
282             so that simply setting the "x" arg of the group
283             fails to move the group. Instead, we have to
284             use gnome_canvas_item_move(), which does the right
285             thing. I see that in GNOME CVS, the current (Sept 2001)
286             version of GNOME Canvas rectifies this issue cleanly.
287         */
288
289         double old_unit_pos;
290         double new_unit_pos = pos / samples_per_unit;
291
292         old_unit_pos = group->property_x();
293
294         if (new_unit_pos != old_unit_pos) {
295                 group->move (new_unit_pos - old_unit_pos, 0.0);
296         }
297
298         if (delta) {
299                 (*delta) = new_unit_pos - old_unit_pos;
300         }
301
302         PositionChanged (frame_position, src); /* EMIT_SIGNAL */
303
304         return true;
305 }
306
307 /** @return position of this item on the timeline */
308 framepos_t
309 TimeAxisViewItem::get_position() const
310 {
311         return frame_position;
312 }
313
314 /**
315  * Set the duration of this item.
316  *
317  * @param dur the new duration of this item
318  * @param src the identity of the object that initiated the change
319  * @return true on success
320  */
321
322 bool
323 TimeAxisViewItem::set_duration (framepos_t dur, void* src)
324 {
325         if ((dur > max_item_duration) || (dur < min_item_duration)) {
326                 warning << string_compose (_("new duration %1 frames is out of bounds for %2"), get_item_name(), dur)
327                         << endmsg;
328                 return false;
329         }
330
331         if (dur == 0) {
332                 group->hide();
333         }
334
335         item_duration = dur;
336
337         reset_width_dependent_items (trackview.editor().frame_to_pixel (dur));
338
339         DurationChanged (dur, src); /* EMIT_SIGNAL */
340         return true;
341 }
342
343 /** @return duration of this item */
344 framepos_t
345 TimeAxisViewItem::get_duration() const
346 {
347         return item_duration;
348 }
349
350 /**
351  * Set the maximum duration that this item can have.
352  *
353  * @param dur the new maximum duration
354  * @param src the identity of the object that initiated the change
355  */
356 void
357 TimeAxisViewItem::set_max_duration(framecnt_t dur, void* src)
358 {
359         max_item_duration = dur;
360         MaxDurationChanged(max_item_duration, src); /* EMIT_SIGNAL */
361 }
362
363 /** @return the maximum duration that this item may have */
364 framecnt_t
365 TimeAxisViewItem::get_max_duration() const
366 {
367         return max_item_duration;
368 }
369
370 /**
371  * Set the minimum duration that this item may have.
372  *
373  * @param the minimum duration that this item may be set to
374  * @param src the identity of the object that initiated the change
375  */
376 void
377 TimeAxisViewItem::set_min_duration(framecnt_t dur, void* src)
378 {
379         min_item_duration = dur;
380         MinDurationChanged(max_item_duration, src); /* EMIT_SIGNAL */
381 }
382
383 /** @return the minimum duration that this item mey have */
384 framecnt_t
385 TimeAxisViewItem::get_min_duration() const
386 {
387         return min_item_duration;
388 }
389
390 /**
391  * Set whether this item is locked to its current position.
392  * Locked items cannot be moved until the item is unlocked again.
393  *
394  * @param yn true to lock this item to its current position
395  * @param src the identity of the object that initiated the change
396  */
397 void
398 TimeAxisViewItem::set_position_locked(bool yn, void* src)
399 {
400         position_locked = yn;
401         set_trim_handle_colors();
402         PositionLockChanged (position_locked, src); /* EMIT_SIGNAL */
403 }
404
405 /** @return true if this item is locked to its current position */
406 bool
407 TimeAxisViewItem::get_position_locked() const
408 {
409         return position_locked;
410 }
411
412 /**
413  * Set whether the maximum duration constraint is active.
414  *
415  * @param active set true to enforce the max duration constraint
416  * @param src the identity of the object that initiated the change
417  */
418 void
419 TimeAxisViewItem::set_max_duration_active (bool active, void* /*src*/)
420 {
421         max_duration_active = active;
422 }
423
424 /** @return true if the maximum duration constraint is active */
425 bool
426 TimeAxisViewItem::get_max_duration_active() const
427 {
428         return max_duration_active;
429 }
430
431 /**
432  * Set whether the minimum duration constraint is active.
433  *
434  * @param active set true to enforce the min duration constraint
435  * @param src the identity of the object that initiated the change
436  */
437
438 void
439 TimeAxisViewItem::set_min_duration_active (bool active, void* /*src*/)
440 {
441         min_duration_active = active;
442 }
443
444 /** @return true if the maximum duration constraint is active */
445 bool
446 TimeAxisViewItem::get_min_duration_active() const
447 {
448         return min_duration_active;
449 }
450
451 /**
452  * Set the name of this item.
453  *
454  * @param new_name the new name of this item
455  * @param src the identity of the object that initiated the change
456  */
457
458 void
459 TimeAxisViewItem::set_item_name(std::string new_name, void* src)
460 {
461         if (new_name != item_name) {
462                 std::string temp_name = item_name;
463                 item_name = new_name;
464                 NameChanged (item_name, temp_name, src); /* EMIT_SIGNAL */
465         }
466 }
467
468 /** @return the name of this item */
469 std::string
470 TimeAxisViewItem::get_item_name() const
471 {
472         return item_name;
473 }
474
475 /**
476  * Set selection status.
477  *
478  * @param yn true if this item is currently selected
479  */
480 void
481 TimeAxisViewItem::set_selected(bool yn)
482 {
483         if (_selected != yn) {
484                 Selectable::set_selected (yn);
485                 set_frame_color ();
486         }
487 }
488
489 /** @return the TimeAxisView that this item is on */
490 TimeAxisView&
491 TimeAxisViewItem::get_time_axis_view () const
492 {
493         return trackview;
494 }
495
496 /**
497  * Set the displayed item text.
498  * This item is the visual text name displayed on the canvas item, this can be different to the name of the item.
499  *
500  * @param new_name the new name text to display
501  */
502
503 void
504 TimeAxisViewItem::set_name_text(const string& new_name)
505 {
506         if (!name_pixbuf) {
507                 return;
508         }
509
510         last_item_width = trackview.editor().frame_to_pixel(item_duration);
511         name_pixbuf_width = pixel_width (new_name, *NAME_FONT) + 2;
512         name_pixbuf->property_pixbuf() = pixbuf_from_string(new_name, NAME_FONT, name_pixbuf_width, NAME_HEIGHT, Gdk::Color ("#000000"));
513 }
514
515
516 /**
517  * Set the height of this item.
518  *
519  * @param h new height
520  */
521 void
522 TimeAxisViewItem::set_height (double height)
523 {
524         _height = height;
525
526         if (name_highlight) {
527                 if (height < NAME_HIGHLIGHT_THRESH) {
528                         name_highlight->hide ();
529                         high_enough_for_name = false;
530
531                 } else {
532                         name_highlight->show();
533                         high_enough_for_name = true;
534                 }
535
536                 if (height > NAME_HIGHLIGHT_SIZE) {
537                         name_highlight->property_y1() = (double) height - 1 - NAME_HIGHLIGHT_SIZE;
538                         name_highlight->property_y2() = (double) height - 1;
539                 }
540                 else {
541                         /* it gets hidden now anyway */
542                         name_highlight->property_y1() = (double) 1.0;
543                         name_highlight->property_y2() = (double) height;
544                 }
545         }
546
547         if (visibility & ShowNameText) {
548                 name_pixbuf->property_y() =  height + 1 - NAME_Y_OFFSET;
549         }
550
551         if (frame) {
552                 frame->property_y2() = height - 1;
553                 if (frame_handle_start) {
554                         frame_handle_start->property_y2() = height - 1;
555                         frame_handle_end->property_y2() = height - 1;
556                 }
557         }
558
559         vestigial_frame->property_y2() = height - 1;
560
561         update_name_pixbuf_visibility ();
562         set_colors ();
563 }
564
565 void
566 TimeAxisViewItem::set_color (Gdk::Color const & base_color)
567 {
568         compute_colors (base_color);
569         set_colors ();
570 }
571
572 ArdourCanvas::Item*
573 TimeAxisViewItem::get_canvas_frame()
574 {
575         return frame;
576 }
577
578 ArdourCanvas::Group*
579 TimeAxisViewItem::get_canvas_group()
580 {
581         return group;
582 }
583
584 ArdourCanvas::Item*
585 TimeAxisViewItem::get_name_highlight()
586 {
587         return name_highlight;
588 }
589
590 ArdourCanvas::Pixbuf*
591 TimeAxisViewItem::get_name_pixbuf()
592 {
593         return name_pixbuf;
594 }
595
596 /**
597  * Calculate some contrasting color for displaying various parts of this item, based upon the base color.
598  *
599  * @param color the base color of the item
600  */
601 void
602 TimeAxisViewItem::compute_colors (Gdk::Color const & base_color)
603 {
604         unsigned char radius;
605         char minor_shift;
606
607         unsigned char r,g,b;
608
609         /* FILL: this is simple */
610         r = base_color.get_red()/256;
611         g = base_color.get_green()/256;
612         b = base_color.get_blue()/256;
613         fill_color = RGBA_TO_UINT(r,g,b,160);
614
615         /*  for minor colors:
616                 if the overall saturation is strong, make the minor colors light.
617                 if its weak, make them dark.
618
619                 we do this by moving an equal distance to the other side of the
620                 central circle in the color wheel from where we started.
621         */
622
623         radius = (unsigned char) rint (floor (sqrt (static_cast<double>(r*r + g*g + b+b))/3.0f));
624         minor_shift = 125 - radius;
625
626         /* LABEL: rotate around color wheel by 120 degrees anti-clockwise */
627
628         r = base_color.get_red()/256;
629         g = base_color.get_green()/256;
630         b = base_color.get_blue()/256;
631
632         if (r > b)
633         {
634                 if (r > g)
635                 {
636                         /* red sector => green */
637                         swap (r,g);
638                 }
639                 else
640                 {
641                         /* green sector => blue */
642                         swap (g,b);
643                 }
644         }
645         else
646         {
647                 if (b > g)
648                 {
649                         /* blue sector => red */
650                         swap (b,r);
651                 }
652                 else
653                 {
654                         /* green sector => blue */
655                         swap (g,b);
656                 }
657         }
658
659         r += minor_shift;
660         b += minor_shift;
661         g += minor_shift;
662
663         label_color = RGBA_TO_UINT(r,g,b,255);
664         r = (base_color.get_red()/256)   + 127;
665         g = (base_color.get_green()/256) + 127;
666         b = (base_color.get_blue()/256)  + 127;
667
668         label_color = RGBA_TO_UINT(r,g,b,255);
669
670         /* XXX can we do better than this ? */
671         /* We're trying;) */
672         /* NUKECOLORS */
673
674         //frame_color_r = 192;
675         //frame_color_g = 192;
676         //frame_color_b = 194;
677
678         //selected_frame_color_r = 182;
679         //selected_frame_color_g = 145;
680         //selected_frame_color_b = 168;
681
682         //handle_color_r = 25;
683         //handle_color_g = 0;
684         //handle_color_b = 255;
685         //lock_handle_color_r = 235;
686         //lock_handle_color_g = 16;
687         //lock_handle_color_b = 16;
688 }
689
690 /**
691  * Convenience method to set the various canvas item colors
692  */
693 void
694 TimeAxisViewItem::set_colors()
695 {
696         set_frame_color();
697
698         if (name_highlight) {
699                 name_highlight->property_fill_color_rgba() = fill_color;
700         }
701         set_trim_handle_colors();
702 }
703
704 /**
705  * Sets the frame color depending on whether this item is selected
706  */
707 void
708 TimeAxisViewItem::set_frame_color()
709 {
710         uint32_t f = 0;
711
712         if (!frame) {
713                 return;
714         }
715         
716         if (_selected) {
717
718                 f = ARDOUR_UI::config()->canvasvar_SelectedFrameBase.get();
719
720                 if (fill_opacity) {
721                         f = UINT_RGBA_CHANGE_A (f, fill_opacity);
722                 } 
723
724                 if (!rect_visible) {
725                         f = UINT_RGBA_CHANGE_A (f, 0);
726                 }
727
728         } else {
729
730                 if (_recregion) {
731                         f = ARDOUR_UI::config()->canvasvar_RecordingRect.get();
732                 } else {
733                         
734                         if (high_enough_for_name && !Config->get_color_regions_using_track_color()) {
735                                 f = ARDOUR_UI::config()->canvasvar_FrameBase.get();
736                         } else {
737                                 f = fill_color;
738                         }
739
740                         if (fill_opacity) {
741                                 f = UINT_RGBA_CHANGE_A (f, fill_opacity);
742                         }
743
744                         if (!rect_visible) {
745                                 f = UINT_RGBA_CHANGE_A (f, 0);
746                         }
747                 }
748         }
749
750         frame->property_fill_color_rgba() = f;
751
752         if (!_recregion) {
753                 f = ARDOUR_UI::config()->canvasvar_TimeAxisFrame.get();
754                 
755                 if (!rect_visible) {
756                         f = UINT_RGBA_CHANGE_A (f, 64);
757                 }
758                 
759                 frame->property_outline_color_rgba() = f;
760         }
761 }
762
763 /**
764  * Set the colors of the start and end trim handle depending on object state
765  */
766 void
767 TimeAxisViewItem::set_trim_handle_colors()
768 {
769         if (frame_handle_start) {
770                 if (position_locked) {
771                         frame_handle_start->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_TrimHandleLocked.get();
772                         frame_handle_end->property_fill_color_rgba() =  ARDOUR_UI::config()->canvasvar_TrimHandleLocked.get();
773                 } else {
774                         frame_handle_start->property_fill_color_rgba() = RGBA_TO_UINT(1, 1, 1, 0); //ARDOUR_UI::config()->canvasvar_TrimHandle.get();
775                         frame_handle_end->property_fill_color_rgba() = RGBA_TO_UINT(1, 1, 1, 0); //ARDOUR_UI::config()->canvasvar_TrimHandle.get();
776                 }
777         }
778 }
779
780 /** @return the samples per unit of this item */
781 double
782 TimeAxisViewItem::get_samples_per_unit()
783 {
784         return samples_per_unit;
785 }
786
787 /**
788  * Set the samples per unit of this item.
789  * This item is used to determine the relative visual size and position of this item
790  * based upon its duration and start value.
791  *
792  * @param spu the new samples per unit value
793  */
794 void
795 TimeAxisViewItem::set_samples_per_unit (double spu)
796 {
797         samples_per_unit = spu;
798         set_position (this->get_position(), this);
799         reset_width_dependent_items ((double)get_duration() / samples_per_unit);
800 }
801
802 void
803 TimeAxisViewItem::reset_width_dependent_items (double pixel_width)
804 {
805         if (pixel_width < GRAB_HANDLE_LENGTH * 2) {
806
807                 if (frame_handle_start) {
808                         frame_handle_start->hide();
809                         frame_handle_end->hide();
810                 }
811
812         }
813
814         if (pixel_width < 2.0) {
815
816                 if (show_vestigial) {
817                         vestigial_frame->show();
818                 }
819
820                 if (name_highlight) {
821                         name_highlight->hide();
822                 }
823
824                 if (frame) {
825                         frame->hide();
826                 }
827
828                 if (frame_handle_start) {
829                         frame_handle_start->hide();
830                         frame_handle_end->hide();
831                 }
832
833                 wide_enough_for_name = false;
834
835         } else {
836                 vestigial_frame->hide();
837
838                 if (name_highlight) {
839
840                         if (_height < NAME_HIGHLIGHT_THRESH) {
841                                 name_highlight->hide();
842                                 high_enough_for_name = false;
843                         } else {
844                                 name_highlight->show();
845                                 if (!get_item_name().empty()) {
846                                         reset_name_width (pixel_width);
847                                 }
848                                 high_enough_for_name = true;
849                         }
850                         
851                         name_highlight->property_x2() = pixel_width;
852                 }
853
854                 if (frame) {
855                         frame->show();
856                         frame->property_x2() = pixel_width;
857                 }
858
859                 if (frame_handle_start) {
860                         if (pixel_width < (2*TimeAxisViewItem::GRAB_HANDLE_LENGTH)) {
861                                 frame_handle_start->hide();
862                                 frame_handle_end->hide();
863                         }
864                         frame_handle_start->show();
865                         frame_handle_end->property_x1() = pixel_width - (TimeAxisViewItem::GRAB_HANDLE_LENGTH);
866                         frame_handle_end->show();
867                         frame_handle_end->property_x2() = pixel_width;
868                 }
869         }
870
871         update_name_pixbuf_visibility ();
872 }
873
874 void
875 TimeAxisViewItem::reset_name_width (double /*pixel_width*/)
876 {
877         uint32_t it_width;
878         int pb_width;
879         bool pixbuf_holds_full_name;
880
881         if (!name_pixbuf) {
882                 return;
883         }
884
885         it_width = trackview.editor().frame_to_pixel(item_duration);
886         pb_width = name_pixbuf_width;
887
888         pixbuf_holds_full_name = last_item_width > pb_width + NAME_X_OFFSET;
889         last_item_width = it_width;
890
891         if (pixbuf_holds_full_name && (it_width >= pb_width + NAME_X_OFFSET)) {
892                 /*
893                   we've previously had the full name length showing 
894                   and its still showing.
895                 */
896                 return;
897         }
898         
899         if (pb_width > it_width - NAME_X_OFFSET) {
900                 pb_width = it_width - NAME_X_OFFSET;
901         }
902         
903         if (it_width <= NAME_X_OFFSET) {
904                 wide_enough_for_name = false;
905         } else {
906                 wide_enough_for_name = true;
907         }
908
909         update_name_pixbuf_visibility ();
910         if (pb_width > 0) {
911                 name_pixbuf->property_pixbuf() = pixbuf_from_string(item_name, NAME_FONT, pb_width, NAME_HEIGHT, Gdk::Color ("#000000"));
912         }
913 }
914
915 /**
916  * Callback used to remove this time axis item during the gtk idle loop.
917  * This is used to avoid deleting the obejct while inside the remove_this_item
918  * method.
919  *
920  * @param item the TimeAxisViewItem to remove.
921  * @param src the identity of the object that initiated the change.
922  */
923 gint
924 TimeAxisViewItem::idle_remove_this_item(TimeAxisViewItem* item, void* src)
925 {
926         item->ItemRemoved (item->get_item_name(), src); /* EMIT_SIGNAL */
927         delete item;
928         item = 0;
929         return false;
930 }
931
932 void
933 TimeAxisViewItem::set_y (double y)
934 {
935         double const old = group->property_y ();
936         if (y != old) {
937                 group->move (0, y - old);
938         }
939 }
940
941 void
942 TimeAxisViewItem::update_name_pixbuf_visibility ()
943 {
944         if (!name_pixbuf) {
945                 return;
946         }
947         
948         if (wide_enough_for_name && high_enough_for_name) {
949                 name_pixbuf->show ();
950         } else {
951                 name_pixbuf->hide ();
952         }
953 }
954
955 void
956 TimeAxisViewItem::parameter_changed (string p)
957 {
958         if (p == "color-regions-using-track-color") {
959                 set_frame_color ();
960         }
961 }