Put some up/down buttons to the right of the summary. Might help with #3786.
[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
160         if (duration == 0) {
161                 warning << "Time Axis Item Duration == 0" << endl;
162         }
163
164         vestigial_frame = new ArdourCanvas::SimpleRect (*group, 0.0, 1.0, 2.0, trackview.current_height());
165         vestigial_frame->hide ();
166         vestigial_frame->property_outline_what() = 0xF;
167         vestigial_frame->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_VestigialFrame.get();
168         vestigial_frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_VestigialFrame.get();
169
170         if (visibility & ShowFrame) {
171                 frame = new ArdourCanvas::SimpleRect (*group, 0.0, 1.0, trackview.editor().frame_to_pixel(duration), trackview.current_height());
172                 
173                 frame->property_outline_pixels() = 1;
174                 frame->property_outline_what() = 0xF;
175                 
176                 if (_recregion) {
177                         frame->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RecordingRect.get();
178                 } else {
179                         frame->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeAxisFrame.get();
180                 }
181                 
182                 frame->property_outline_what() = 0x1|0x2|0x4|0x8;
183
184         } else {
185                 frame = 0;
186         }
187
188         if (visibility & ShowNameHighlight) {
189                 
190                 if (visibility & FullWidthNameHighlight) {
191                         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());
192                 } else {
193                         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());
194                 }
195                 
196                 name_highlight->set_data ("timeaxisviewitem", this);
197                 name_highlight->property_outline_what() = 0x4;
198                 /* we should really use a canvas color property here */
199                 name_highlight->property_outline_color_rgba() = RGBA_TO_UINT (0,0,0,255);
200
201         } else {
202                 name_highlight = 0;
203         }
204
205         if (visibility & ShowNameText) {
206                 name_pixbuf = new ArdourCanvas::Pixbuf(*group);
207                 name_pixbuf->property_x() = NAME_X_OFFSET;
208                 name_pixbuf->property_y() = trackview.current_height() + 1 - NAME_Y_OFFSET;
209
210         } else {
211                 name_pixbuf = 0;
212         }
213
214         /* create our grab handles used for trimming/duration etc */
215         if (!_recregion && !_automation) {
216                 frame_handle_start = new ArdourCanvas::SimpleRect (*group, 0.0, TimeAxisViewItem::GRAB_HANDLE_LENGTH, 5.0, trackview.current_height());
217                 frame_handle_start->property_outline_what() = 0x0;
218                 frame_handle_end = new ArdourCanvas::SimpleRect (*group, 0.0, TimeAxisViewItem::GRAB_HANDLE_LENGTH, 5.0, trackview.current_height());
219                 frame_handle_end->property_outline_what() = 0x0;
220         } else {
221                 frame_handle_start = frame_handle_end = 0;
222         }
223
224         set_color (base_color);
225
226         set_duration (item_duration, this);
227         set_position (start, this);
228
229         Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&TimeAxisViewItem::parameter_changed, this, _1), gui_context ());
230 }
231
232 TimeAxisViewItem::~TimeAxisViewItem()
233 {
234         delete group;
235 }
236
237
238 /**
239  * Set the position of this item on the timeline.
240  *
241  * @param pos the new position
242  * @param src the identity of the object that initiated the change
243  * @return true on success
244  */
245
246 bool
247 TimeAxisViewItem::set_position(framepos_t pos, void* src, double* delta)
248 {
249         if (position_locked) {
250                 return false;
251         }
252
253         frame_position = pos;
254
255         /*  This sucks. The GnomeCanvas version I am using
256             doesn't correctly implement gnome_canvas_group_set_arg(),
257             so that simply setting the "x" arg of the group
258             fails to move the group. Instead, we have to
259             use gnome_canvas_item_move(), which does the right
260             thing. I see that in GNOME CVS, the current (Sept 2001)
261             version of GNOME Canvas rectifies this issue cleanly.
262         */
263
264         double old_unit_pos;
265         double new_unit_pos = pos / samples_per_unit;
266
267         old_unit_pos = group->property_x();
268
269         if (new_unit_pos != old_unit_pos) {
270                 group->move (new_unit_pos - old_unit_pos, 0.0);
271         }
272
273         if (delta) {
274                 (*delta) = new_unit_pos - old_unit_pos;
275         }
276
277         PositionChanged (frame_position, src); /* EMIT_SIGNAL */
278
279         return true;
280 }
281
282 /** @return position of this item on the timeline */
283 framepos_t
284 TimeAxisViewItem::get_position() const
285 {
286         return frame_position;
287 }
288
289 /**
290  * Set the duration of this item.
291  *
292  * @param dur the new duration of this item
293  * @param src the identity of the object that initiated the change
294  * @return true on success
295  */
296
297 bool
298 TimeAxisViewItem::set_duration (framepos_t dur, void* src)
299 {
300         if ((dur > max_item_duration) || (dur < min_item_duration)) {
301                 warning << string_compose (_("new duration %1 frames is out of bounds for %2"), get_item_name(), dur)
302                         << endmsg;
303                 return false;
304         }
305
306         if (dur == 0) {
307                 group->hide();
308         }
309
310         item_duration = dur;
311
312         reset_width_dependent_items (trackview.editor().frame_to_pixel (dur));
313
314         DurationChanged (dur, src); /* EMIT_SIGNAL */
315         return true;
316 }
317
318 /** @return duration of this item */
319 framepos_t
320 TimeAxisViewItem::get_duration() const
321 {
322         return item_duration;
323 }
324
325 /**
326  * Set the maximum duration that this item can have.
327  *
328  * @param dur the new maximum duration
329  * @param src the identity of the object that initiated the change
330  */
331 void
332 TimeAxisViewItem::set_max_duration(framecnt_t dur, void* src)
333 {
334         max_item_duration = dur;
335         MaxDurationChanged(max_item_duration, src); /* EMIT_SIGNAL */
336 }
337
338 /** @return the maximum duration that this item may have */
339 framecnt_t
340 TimeAxisViewItem::get_max_duration() const
341 {
342         return max_item_duration;
343 }
344
345 /**
346  * Set the minimum duration that this item may have.
347  *
348  * @param the minimum duration that this item may be set to
349  * @param src the identity of the object that initiated the change
350  */
351 void
352 TimeAxisViewItem::set_min_duration(framecnt_t dur, void* src)
353 {
354         min_item_duration = dur;
355         MinDurationChanged(max_item_duration, src); /* EMIT_SIGNAL */
356 }
357
358 /** @return the minimum duration that this item mey have */
359 framecnt_t
360 TimeAxisViewItem::get_min_duration() const
361 {
362         return min_item_duration;
363 }
364
365 /**
366  * Set whether this item is locked to its current position.
367  * Locked items cannot be moved until the item is unlocked again.
368  *
369  * @param yn true to lock this item to its current position
370  * @param src the identity of the object that initiated the change
371  */
372 void
373 TimeAxisViewItem::set_position_locked(bool yn, void* src)
374 {
375         position_locked = yn;
376         set_trim_handle_colors();
377         PositionLockChanged (position_locked, src); /* EMIT_SIGNAL */
378 }
379
380 /** @return true if this item is locked to its current position */
381 bool
382 TimeAxisViewItem::get_position_locked() const
383 {
384         return position_locked;
385 }
386
387 /**
388  * Set whether the maximum duration constraint is active.
389  *
390  * @param active set true to enforce the max duration constraint
391  * @param src the identity of the object that initiated the change
392  */
393 void
394 TimeAxisViewItem::set_max_duration_active (bool active, void* /*src*/)
395 {
396         max_duration_active = active;
397 }
398
399 /** @return true if the maximum duration constraint is active */
400 bool
401 TimeAxisViewItem::get_max_duration_active() const
402 {
403         return max_duration_active;
404 }
405
406 /**
407  * Set whether the minimum duration constraint is active.
408  *
409  * @param active set true to enforce the min duration constraint
410  * @param src the identity of the object that initiated the change
411  */
412
413 void
414 TimeAxisViewItem::set_min_duration_active (bool active, void* /*src*/)
415 {
416         min_duration_active = active;
417 }
418
419 /** @return true if the maximum duration constraint is active */
420 bool
421 TimeAxisViewItem::get_min_duration_active() const
422 {
423         return min_duration_active;
424 }
425
426 /**
427  * Set the name of this item.
428  *
429  * @param new_name the new name of this item
430  * @param src the identity of the object that initiated the change
431  */
432
433 void
434 TimeAxisViewItem::set_item_name(std::string new_name, void* src)
435 {
436         if (new_name != item_name) {
437                 std::string temp_name = item_name;
438                 item_name = new_name;
439                 NameChanged (item_name, temp_name, src); /* EMIT_SIGNAL */
440         }
441 }
442
443 /** @return the name of this item */
444 std::string
445 TimeAxisViewItem::get_item_name() const
446 {
447         return item_name;
448 }
449
450 /**
451  * Set selection status.
452  *
453  * @param yn true if this item is currently selected
454  */
455 void
456 TimeAxisViewItem::set_selected(bool yn)
457 {
458         if (_selected != yn) {
459                 Selectable::set_selected (yn);
460                 set_frame_color ();
461         }
462 }
463
464 /** @return the TimeAxisView that this item is on */
465 TimeAxisView&
466 TimeAxisViewItem::get_time_axis_view () const
467 {
468         return trackview;
469 }
470
471 /**
472  * Set the displayed item text.
473  * This item is the visual text name displayed on the canvas item, this can be different to the name of the item.
474  *
475  * @param new_name the new name text to display
476  */
477
478 void
479 TimeAxisViewItem::set_name_text(const string& new_name)
480 {
481         if (!name_pixbuf) {
482                 return;
483         }
484
485         last_item_width = trackview.editor().frame_to_pixel(item_duration);
486         name_pixbuf_width = pixel_width (new_name, *NAME_FONT) + 2;
487         name_pixbuf->property_pixbuf() = pixbuf_from_string(new_name, NAME_FONT, name_pixbuf_width, NAME_HEIGHT, Gdk::Color ("#000000"));
488 }
489
490
491 /**
492  * Set the height of this item.
493  *
494  * @param h new height
495  */
496 void
497 TimeAxisViewItem::set_height (double height)
498 {
499         _height = height;
500
501         if (name_highlight) {
502                 if (height < NAME_HIGHLIGHT_THRESH) {
503                         name_highlight->hide ();
504                         high_enough_for_name = false;
505
506                 } else {
507                         name_highlight->show();
508                         high_enough_for_name = true;
509                 }
510
511                 if (height > NAME_HIGHLIGHT_SIZE) {
512                         name_highlight->property_y1() = (double) height - 1 - NAME_HIGHLIGHT_SIZE;
513                         name_highlight->property_y2() = (double) height - 1;
514                 }
515                 else {
516                         /* it gets hidden now anyway */
517                         name_highlight->property_y1() = (double) 1.0;
518                         name_highlight->property_y2() = (double) height;
519                 }
520         }
521
522         if (visibility & ShowNameText) {
523                 name_pixbuf->property_y() =  height + 1 - NAME_Y_OFFSET;
524         }
525
526         if (frame) {
527                 frame->property_y2() = height - 1;
528                 if (frame_handle_start) {
529                         frame_handle_start->property_y2() = height - 1;
530                         frame_handle_end->property_y2() = height - 1;
531                 }
532         }
533
534         vestigial_frame->property_y2() = height - 1;
535
536         update_name_pixbuf_visibility ();
537         set_colors ();
538 }
539
540 void
541 TimeAxisViewItem::set_color (Gdk::Color const & base_color)
542 {
543         compute_colors (base_color);
544         set_colors ();
545 }
546
547 ArdourCanvas::Item*
548 TimeAxisViewItem::get_canvas_frame()
549 {
550         return frame;
551 }
552
553 ArdourCanvas::Group*
554 TimeAxisViewItem::get_canvas_group()
555 {
556         return group;
557 }
558
559 ArdourCanvas::Item*
560 TimeAxisViewItem::get_name_highlight()
561 {
562         return name_highlight;
563 }
564
565 ArdourCanvas::Pixbuf*
566 TimeAxisViewItem::get_name_pixbuf()
567 {
568         return name_pixbuf;
569 }
570
571 /**
572  * Calculate some contrasting color for displaying various parts of this item, based upon the base color.
573  *
574  * @param color the base color of the item
575  */
576 void
577 TimeAxisViewItem::compute_colors (Gdk::Color const & base_color)
578 {
579         unsigned char radius;
580         char minor_shift;
581
582         unsigned char r,g,b;
583
584         /* FILL: this is simple */
585         r = base_color.get_red()/256;
586         g = base_color.get_green()/256;
587         b = base_color.get_blue()/256;
588         fill_color = RGBA_TO_UINT(r,g,b,160);
589
590         /*  for minor colors:
591                 if the overall saturation is strong, make the minor colors light.
592                 if its weak, make them dark.
593
594                 we do this by moving an equal distance to the other side of the
595                 central circle in the color wheel from where we started.
596         */
597
598         radius = (unsigned char) rint (floor (sqrt (static_cast<double>(r*r + g*g + b+b))/3.0f));
599         minor_shift = 125 - radius;
600
601         /* LABEL: rotate around color wheel by 120 degrees anti-clockwise */
602
603         r = base_color.get_red()/256;
604         g = base_color.get_green()/256;
605         b = base_color.get_blue()/256;
606
607         if (r > b)
608         {
609                 if (r > g)
610                 {
611                         /* red sector => green */
612                         swap (r,g);
613                 }
614                 else
615                 {
616                         /* green sector => blue */
617                         swap (g,b);
618                 }
619         }
620         else
621         {
622                 if (b > g)
623                 {
624                         /* blue sector => red */
625                         swap (b,r);
626                 }
627                 else
628                 {
629                         /* green sector => blue */
630                         swap (g,b);
631                 }
632         }
633
634         r += minor_shift;
635         b += minor_shift;
636         g += minor_shift;
637
638         label_color = RGBA_TO_UINT(r,g,b,255);
639         r = (base_color.get_red()/256)   + 127;
640         g = (base_color.get_green()/256) + 127;
641         b = (base_color.get_blue()/256)  + 127;
642
643         label_color = RGBA_TO_UINT(r,g,b,255);
644
645         /* XXX can we do better than this ? */
646         /* We're trying;) */
647         /* NUKECOLORS */
648
649         //frame_color_r = 192;
650         //frame_color_g = 192;
651         //frame_color_b = 194;
652
653         //selected_frame_color_r = 182;
654         //selected_frame_color_g = 145;
655         //selected_frame_color_b = 168;
656
657         //handle_color_r = 25;
658         //handle_color_g = 0;
659         //handle_color_b = 255;
660         //lock_handle_color_r = 235;
661         //lock_handle_color_g = 16;
662         //lock_handle_color_b = 16;
663 }
664
665 /**
666  * Convenience method to set the various canvas item colors
667  */
668 void
669 TimeAxisViewItem::set_colors()
670 {
671         set_frame_color();
672
673         if (name_highlight) {
674                 name_highlight->property_fill_color_rgba() = fill_color;
675         }
676         set_trim_handle_colors();
677 }
678
679 /**
680  * Sets the frame color depending on whether this item is selected
681  */
682 void
683 TimeAxisViewItem::set_frame_color()
684 {
685         if (!frame) {
686                 return;
687         }
688         
689         if (_selected) {
690                 if (fill_opacity) {
691                         frame->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (ARDOUR_UI::config()->canvasvar_SelectedFrameBase.get(), fill_opacity);
692                 } else {
693                         frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedFrameBase.get();
694                 }
695         } else {
696                 if (_recregion) {
697                         frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RecordingRect.get();
698                 } else {
699                         uint32_t f = 0;
700                         if (high_enough_for_name && !Config->get_color_regions_using_track_color()) {
701                                 f = ARDOUR_UI::config()->canvasvar_FrameBase.get();
702                         } else {
703                                 f = fill_color;
704                         }
705
706                         if (fill_opacity) {
707                                 f = UINT_RGBA_CHANGE_A (f, fill_opacity);
708                         }
709
710                         frame->property_fill_color_rgba() = f;
711                 }
712         }
713 }
714
715 /**
716  * Set the colors of the start and end trim handle depending on object state
717  */
718 void
719 TimeAxisViewItem::set_trim_handle_colors()
720 {
721         if (frame_handle_start) {
722                 if (position_locked) {
723                         frame_handle_start->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_TrimHandleLocked.get();
724                         frame_handle_end->property_fill_color_rgba() =  ARDOUR_UI::config()->canvasvar_TrimHandleLocked.get();
725                 } else {
726                         frame_handle_start->property_fill_color_rgba() = RGBA_TO_UINT(1, 1, 1, 0); //ARDOUR_UI::config()->canvasvar_TrimHandle.get();
727                         frame_handle_end->property_fill_color_rgba() = RGBA_TO_UINT(1, 1, 1, 0); //ARDOUR_UI::config()->canvasvar_TrimHandle.get();
728                 }
729         }
730 }
731
732 /** @return the samples per unit of this item */
733 double
734 TimeAxisViewItem::get_samples_per_unit()
735 {
736         return samples_per_unit;
737 }
738
739 /**
740  * Set the samples per unit of this item.
741  * This item is used to determine the relative visual size and position of this item
742  * based upon its duration and start value.
743  *
744  * @param spu the new samples per unit value
745  */
746 void
747 TimeAxisViewItem::set_samples_per_unit (double spu)
748 {
749         samples_per_unit = spu;
750         set_position (this->get_position(), this);
751         reset_width_dependent_items ((double)get_duration() / samples_per_unit);
752 }
753
754 void
755 TimeAxisViewItem::reset_width_dependent_items (double pixel_width)
756 {
757         if (pixel_width < GRAB_HANDLE_LENGTH * 2) {
758
759                 if (frame_handle_start) {
760                         frame_handle_start->hide();
761                         frame_handle_end->hide();
762                 }
763
764         }
765
766         if (pixel_width < 2.0) {
767
768                 if (show_vestigial) {
769                         vestigial_frame->show();
770                 }
771
772                 if (name_highlight) {
773                         name_highlight->hide();
774                 }
775
776                 if (frame) {
777                         frame->hide();
778                 }
779
780                 if (frame_handle_start) {
781                         frame_handle_start->hide();
782                         frame_handle_end->hide();
783                 }
784
785                 wide_enough_for_name = false;
786
787         } else {
788                 vestigial_frame->hide();
789
790                 if (name_highlight) {
791
792                         if (_height < NAME_HIGHLIGHT_THRESH) {
793                                 name_highlight->hide();
794                                 high_enough_for_name = false;
795                         } else {
796                                 name_highlight->show();
797                                 if (!get_item_name().empty()) {
798                                         reset_name_width (pixel_width);
799                                 }
800                                 high_enough_for_name = true;
801                         }
802                         
803                         name_highlight->property_x2() = pixel_width;
804                 }
805
806                 if (frame) {
807                         frame->show();
808                         frame->property_x2() = pixel_width;
809                 }
810
811                 if (frame_handle_start) {
812                         if (pixel_width < (2*TimeAxisViewItem::GRAB_HANDLE_LENGTH)) {
813                                 frame_handle_start->hide();
814                                 frame_handle_end->hide();
815                         }
816                         frame_handle_start->show();
817                         frame_handle_end->property_x1() = pixel_width - (TimeAxisViewItem::GRAB_HANDLE_LENGTH);
818                         frame_handle_end->show();
819                         frame_handle_end->property_x2() = pixel_width;
820                 }
821         }
822
823         update_name_pixbuf_visibility ();
824 }
825
826 void
827 TimeAxisViewItem::reset_name_width (double /*pixel_width*/)
828 {
829         uint32_t it_width;
830         int pb_width;
831         bool pixbuf_holds_full_name;
832
833         if (!name_pixbuf) {
834                 return;
835         }
836
837         it_width = trackview.editor().frame_to_pixel(item_duration);
838         pb_width = name_pixbuf_width;
839
840         pixbuf_holds_full_name = last_item_width > pb_width + NAME_X_OFFSET;
841         last_item_width = it_width;
842
843         if (pixbuf_holds_full_name && (it_width >= pb_width + NAME_X_OFFSET)) {
844                 /*
845                   we've previously had the full name length showing 
846                   and its still showing.
847                 */
848                 return;
849         }
850         
851         if (pb_width > it_width - NAME_X_OFFSET) {
852                 pb_width = it_width - NAME_X_OFFSET;
853         }
854         
855         if (it_width <= NAME_X_OFFSET) {
856                 wide_enough_for_name = false;
857         } else {
858                 wide_enough_for_name = true;
859         }
860
861         update_name_pixbuf_visibility ();
862         if (pb_width > 0) {
863                 name_pixbuf->property_pixbuf() = pixbuf_from_string(item_name, NAME_FONT, pb_width, NAME_HEIGHT, Gdk::Color ("#000000"));
864         }
865 }
866
867 /**
868  * Callback used to remove this time axis item during the gtk idle loop.
869  * This is used to avoid deleting the obejct while inside the remove_this_item
870  * method.
871  *
872  * @param item the TimeAxisViewItem to remove.
873  * @param src the identity of the object that initiated the change.
874  */
875 gint
876 TimeAxisViewItem::idle_remove_this_item(TimeAxisViewItem* item, void* src)
877 {
878         item->ItemRemoved (item->get_item_name(), src); /* EMIT_SIGNAL */
879         delete item;
880         item = 0;
881         return false;
882 }
883
884 void
885 TimeAxisViewItem::set_y (double y)
886 {
887         double const old = group->property_y ();
888         if (y != old) {
889                 group->move (0, y - old);
890         }
891 }
892
893 void
894 TimeAxisViewItem::update_name_pixbuf_visibility ()
895 {
896         if (!name_pixbuf) {
897                 return;
898         }
899         
900         if (wide_enough_for_name && high_enough_for_name) {
901                 name_pixbuf->show ();
902         } else {
903                 name_pixbuf->hide ();
904         }
905 }
906
907 void
908 TimeAxisViewItem::parameter_changed (string p)
909 {
910         if (p == "color-regions-using-track-color") {
911                 set_frame_color ();
912         }
913 }