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