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