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