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