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