Initial commit
[fillmore] / src / marina / TrackView.vala
1 /* Copyright 2009-2010 Yorba Foundation
2  *
3  * This software is licensed under the GNU Lesser General Public License
4  * (version 2.1 or later).  See the COPYING file in this distribution. 
5  */
6
7 using Logging;
8
9 class TrackViewConcrete : TrackView, Gtk.Fixed {
10     Model.Track track;
11     TimeLine timeline;
12     TransportDelegate transport_delegate;
13
14     const int clip_height = 64;
15     const int TrackHeight = clip_height + TimeLine.BORDER * 2;
16
17     public TrackViewConcrete(TransportDelegate transport_delegate, 
18             Model.Track track, TimeLine timeline) {
19         this.track = track;
20         this.timeline = timeline;
21         this.transport_delegate = transport_delegate;
22
23         track.clip_added.connect(on_clip_added);
24         track.clip_removed.connect(on_clip_removed);
25     }
26
27     override void size_request(out Gtk.Requisition requisition) {
28         base.size_request(out requisition);
29         requisition.height = TrackHeight;
30         requisition.width += TimeLine.BORDER;    // right margin
31     }
32
33     void on_clip_moved(ClipView clip) {
34         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_clip_moved");
35         set_clip_pos(clip);
36     }
37
38     void on_clip_deleted(Model.Clip clip) {
39         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_clip_deleted");
40         track.delete_clip(clip);
41         clear_drag();
42     }
43
44     void on_clip_added(Model.Track t, Model.Clip clip, bool select) {
45         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_clip_added");
46         ClipView view = new ClipView(transport_delegate, clip, timeline.provider, clip_height);
47         view.clip_moved.connect(on_clip_moved);
48         view.clip_deleted.connect(on_clip_deleted);
49         view.move_begin.connect(on_move_begin);
50         view.trim_begin.connect(on_trim_begin);
51
52         put(view, timeline.provider.time_to_xpos(clip.start), TimeLine.BORDER);
53         view.show();
54
55         timeline.track_changed();
56         clip_view_added(view);
57         if (select) {
58             view.selection_request(view, false);
59         }
60     }
61
62     // TODO: This method should not be public.  When linking/grouping is done, this method
63     // should become private.  See Timeline.on_clip_view_move_begin for more information.
64     public void move_to_top(ClipView clip_view) {
65         /*
66         * We remove the ClipView from the Fixed object and add it again to make
67         * sure that when we draw it, it is displayed above every other clip while
68         * dragging.
69         */
70         remove(clip_view);
71         put(clip_view, 
72             timeline.provider.time_to_xpos(clip_view.clip.start),
73             TimeLine.BORDER);
74         clip_view.show();
75     }
76
77     void on_trim_begin(ClipView clip_view) {
78         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_trim_begin");
79         move_to_top(clip_view);
80     }
81
82     void on_move_begin(ClipView clip_view, bool do_copy) {
83         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_move_begin");
84         move_to_top(clip_view);
85     }
86
87     void set_clip_pos(ClipView view) {
88         move(view, timeline.provider.time_to_xpos(view.clip.start), TimeLine.BORDER);
89         queue_draw();
90     }
91
92     public void resize() {
93         foreach (Gtk.Widget w in get_children()) {
94             ClipView view = w as ClipView;
95             if (view != null) {
96                 view.on_clip_moved(view.clip);
97             }
98         }
99     }
100
101     void on_clip_removed(Model.Clip clip) {
102         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_clip_removed");
103         foreach (Gtk.Widget w in get_children()) {
104             ClipView view = w as ClipView;
105             if (view.clip == clip) {
106                 view.clip_moved.disconnect(on_clip_moved);
107                 remove(view);
108                 timeline.track_changed();
109                 return;
110             }
111         }
112     }
113
114 /*
115     void unselect_gap() {
116         if (timeline.gap_view != null) {
117             TrackView parent = timeline.gap_view.parent as TrackView;
118             parent.remove(timeline.gap_view);
119             timeline.gap_view = null;
120         }
121     }
122 */
123
124     override bool button_press_event(Gdk.EventButton e) {
125         if (e.type != Gdk.EventType.BUTTON_PRESS &&
126             e.type != Gdk.EventType.2BUTTON_PRESS &&
127             e.type != Gdk.EventType.3BUTTON_PRESS)
128             return false;
129
130         if (e.button == 1 ||
131             e.button == 3) {
132 /*
133             int x = (int) e.x;
134             int64 time = timeline.provider.xpos_to_time(x);
135             Model.Gap g;
136             track.find_containing_gap(time, out g);
137             if (g.end > g.start) {
138                 int64 length = g.end - g.start;
139                 int width = timeline.provider.time_to_xpos(g.start + length) -
140                     timeline.provider.time_to_xpos(g.start);            
141                 
142                 timeline.gap_view = new GapView(g.start, length, 
143                     width, clip_height);
144                 timeline.gap_view.removed += on_gap_view_removed;
145                 timeline.gap_view.unselected += on_gap_view_unselected;
146                 put(timeline.gap_view, timeline.provider.time_to_xpos(g.start), TimeLine.BORDER);
147                 timeline.gap_view.show();
148             }
149 */
150             timeline.deselect_all_clips();
151             /*
152             track.set_selected(true);
153             */
154         }
155         return false;
156     }
157     
158 /*
159     void on_gap_view_removed(GapView gap_view) {
160         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_gap_view_removed");
161         track.delete_gap(gap_view.gap);
162     }
163
164     void on_gap_view_unselected(GapView gap_view) {
165         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_gap_view_unselected");
166         unselect_gap();
167     }
168 */
169     void clear_drag() {
170         window.set_cursor(null);
171         queue_draw();
172     }
173
174     public Model.Track get_track() {
175         return track;
176     }
177     
178     public int get_track_height() {
179         return TrackHeight;
180     }
181     
182     public Gtk.Widget? find_child(double x, double y) {
183         foreach (Gtk.Widget w in get_children()) {
184             if (w.allocation.x <= x && x < w.allocation.x + w.allocation.width) {
185                 return w;
186             }
187         }
188         return null;
189     }
190     
191     public void select_all() {
192         foreach (Gtk.Widget child in get_children()) {
193             ClipView? clip_view = child as ClipView;
194             if (clip_view != null) {
195                 clip_view.select();
196             }
197         }
198     }
199 }