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