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