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