Initial commit
[fillmore] / src / fillmore / header_area.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 TrackHeader : Gtk.EventBox {
10     protected weak Model.Track track;
11     protected weak HeaderArea header_area;
12     protected Gtk.Label track_label;
13     
14     public const int width = 100;
15     
16     public TrackHeader(Model.Track track, HeaderArea area, int height) {
17         this.track = track;
18         this.header_area = area;
19         
20         track.track_renamed.connect(on_track_renamed);
21         track.track_selection_changed.connect(on_track_selection_changed);
22         set_size_request(width, height);
23         modify_bg(Gtk.StateType.NORMAL, header_area.background_color);
24         modify_bg(Gtk.StateType.SELECTED, parse_color("#68a"));
25         
26         track_label = new Gtk.Label(track.display_name);
27         track_label.modify_fg(Gtk.StateType.NORMAL, parse_color("#fff"));
28     }
29     
30     void on_track_renamed() {
31         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_track_renamed");
32         track_label.set_text(track.display_name);
33     }
34     
35     void on_track_selection_changed(Model.Track track) {
36         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_track_selection_changed");
37         set_state(track.get_is_selected() ? Gtk.StateType.SELECTED : Gtk.StateType.NORMAL);
38     }
39     
40     public override bool button_press_event(Gdk.EventButton event) {
41         header_area.select(track);
42         return true;
43     }
44     
45     public Model.Track get_track() {
46         return track;
47     }
48 }
49
50 public class SliderBase : Gtk.HScrollbar {
51     Gdk.Pixbuf slider_image;
52     construct {
53         can_focus = true;
54         try {
55             slider_image = new Gdk.Pixbuf.from_file(
56                 AppDirs.get_resources_dir().get_child("dot.png").get_path());
57         } catch (GLib.Error e) {
58             warning("Could not load resource for slider: %s", e.message);
59         }
60     }
61     
62     public override bool expose_event (Gdk.EventExpose event) {
63         Gdk.GC gc = style.fg_gc[(int) Gtk.StateType.NORMAL];
64         int radius = (slider_end - slider_start) / 2;
65         int center = allocation.x + slider_start + radius;
66         int height = allocation.y + allocation.height / 2;
67
68         event.window.draw_rectangle(gc, false,
69             allocation.x + radius, height - 2, allocation.width - 2 * radius, 1);
70
71         event.window.draw_pixbuf(gc, slider_image, 0, 0, center - radius, allocation.y + 2, 
72             slider_image.get_width(), slider_image.get_height(), Gdk.RgbDither.NORMAL, 0, 0);
73         return true;
74     }
75 }
76
77 class PanSlider : SliderBase {
78     construct {
79     }
80 }
81
82 public class VolumeSlider : SliderBase {
83     construct {
84     }
85 }
86
87 class AudioTrackHeader : TrackHeader {
88     public double panorama;
89     public double volume;
90     
91     public AudioTrackHeader(Model.AudioTrack track, HeaderArea header, int height) {
92         base(track, header, height);
93         
94         track_label.modify_font(Pango.FontDescription.from_string("Sans 10"));
95         track_label.set_padding(4, 2);
96         track_label.set_alignment(0,0);
97         
98         track.parameter_changed.connect(on_parameter_changed);
99         
100         volume = track.get_volume();
101         panorama = track.get_pan();
102         
103         Gtk.VBox vbox = new Gtk.VBox(false, 0);
104         vbox.pack_start(track_label, true, true, 0);
105         Hildon.Button volpan_button = new Hildon.Button(Hildon.SizeType.AUTO_HEIGHT | Hildon.SizeType.AUTO_WIDTH, Hildon.ButtonArrangement.HORIZONTAL);
106         //volpan_button.set_text("Vol", "");
107         volpan_button.set_image(new Gtk.Image.from_icon_name("statusarea_volumelevel4", Gtk.IconSize.BUTTON));
108         volpan_button.set_image_position(Gtk.PositionType.LEFT);
109         volpan_button.clicked.connect(do_volpan_popup);
110         vbox.add(volpan_button);
111         
112         //View.AudioMeter meter = new View.AudioMeter(track);
113         //vbox.add(meter);        
114         //vbox.add(volume_box);
115         //vbox.add(pan_box);
116         add(vbox);
117     }
118     
119     void do_volpan_popup() {
120       IdWorks.VolumeAndPanPopUp dlg = new IdWorks.VolumeAndPanPopUp(this, "Volume / Pan: " + track.display_name);
121       //dlg.set_transient_for(this.get_transient_for());
122       dlg.set_volume(this.volume);
123       dlg.set_panorama(this.panorama);
124       dlg.volume_updated.connect(on_volume_updated);
125       dlg.panorama_updated.connect(on_panorama_updated);
126       dlg.run();
127       dlg.destroy();
128       dlg = null;
129     }
130     
131     void on_panorama_updated(double val) {
132         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_pan_value_changed");
133         Model.AudioTrack audio_track = track as Model.AudioTrack;
134         if (audio_track != null) {
135             audio_track.set_pan(val);
136         }
137     }
138
139     /*void on_pan_value_changed() {
140         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_pan_value_changed");
141         Model.AudioTrack audio_track = track as Model.AudioTrack;
142         if (audio_track != null) {
143             Gtk.Adjustment adjustment = pan.get_adjustment();
144             audio_track.set_pan(adjustment.get_value());
145         }
146     }*/
147     
148     void on_volume_updated(double val) {
149         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_volume_value_changed");
150         Model.AudioTrack audio_track = track as Model.AudioTrack;
151         if (audio_track != null) {
152             audio_track.set_volume(val);
153         }
154     }
155     
156     /*void on_volume_value_changed() {
157         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_volume_value_changed");
158         Model.AudioTrack audio_track = track as Model.AudioTrack;
159         if (audio_track != null) {
160             Gtk.Adjustment adjustment = volume.get_adjustment();
161             audio_track.set_volume(adjustment.get_value());
162         }
163     }*/
164     void on_parameter_changed(Model.Parameter parameter, double new_value) {
165         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_parameter_changed");
166         Model.AudioTrack audio_track = track as Model.AudioTrack;
167         assert(audio_track != null);
168         switch(parameter) {
169             case Model.Parameter.VOLUME:
170                 volume = new_value;
171             break;
172             case Model.Parameter.PAN:
173                 panorama = new_value;
174             break;
175         }
176     }
177    /* void on_parameter_changed(Model.Parameter parameter, double new_value) {
178         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_parameter_changed");
179         Model.AudioTrack audio_track = track as Model.AudioTrack;
180         assert(audio_track != null);
181         switch(parameter) {
182             case Model.Parameter.VOLUME:
183                 volume.set_value(new_value);
184             break;
185             case Model.Parameter.PAN:
186                 pan.set_value(new_value);
187             break;
188         }
189     }*/
190 }
191
192 class HeaderArea : Gtk.EventBox {
193     weak Model.Project project;
194     
195     Gtk.VBox vbox;
196     public Gdk.Color background_color = parse_color("#666");
197     
198     public HeaderArea(Recorder recorder, Model.TimeSystem provider, int height) {
199         this.project = recorder.project;
200         recorder.timeline.trackview_removed.connect(on_trackview_removed);
201         recorder.timeline.trackview_added.connect(on_trackview_added);
202         
203         set_size_request(TrackHeader.width, 0);
204         modify_bg(Gtk.StateType.NORMAL, background_color);
205         
206         vbox = new Gtk.VBox(false, 0);
207         add(vbox);
208         Gtk.DrawingArea status_bar = new View.StatusBar(project, provider, height);
209         
210         vbox.pack_start(status_bar, false, false, 0);
211
212         vbox.pack_start(new TrackSeparator(), false, false, 0);
213         
214         foreach (TrackView track in recorder.timeline.tracks) {
215             on_trackview_added(track);
216         }
217     }
218     
219     public void on_trackview_added(TrackView trackview) {
220         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_trackview_added");
221         Model.AudioTrack audio_track = trackview.get_track() as Model.AudioTrack;
222         assert(audio_track != null);
223         //we are currently only supporting audio tracks.  We'll probably have
224         //a separate method for adding video track, midi track, aux input, etc
225
226         TrackHeader header = new AudioTrackHeader(audio_track, this, trackview.get_track_height());
227         vbox.pack_start(header, false, false, 0);
228         vbox.pack_start(new TrackSeparator(), false, false, 0);
229         vbox.show_all();
230         select(audio_track);
231     }
232     
233     public void on_trackview_removed(TrackView trackview) {
234         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_trackview_removed");
235         Model.Track track = trackview.get_track();
236         TrackHeader? my_track_header = null;
237         Gtk.HSeparator? my_separator = null;
238         foreach(Gtk.Widget widget in vbox.get_children()) {
239             if (my_track_header == null) {
240                 TrackHeader? track_header = widget as TrackHeader;
241                 if (track_header != null && track_header.get_track() == track) {
242                     my_track_header = track_header;
243                 }
244             } else {
245                 my_separator = widget as Gtk.HSeparator;
246                 break;
247             }
248         }
249         
250         if (my_track_header != null) {
251             vbox.remove(my_track_header);
252         }
253         
254         if (my_separator != null) {
255             vbox.remove(my_separator);
256         }
257
258         if (project.tracks.size != 0) {
259             select(project.tracks[0]);
260         }
261     }
262     
263     public void select(Model.Track track) {
264         foreach (Model.Track t in project.tracks)
265             t.set_selected(t == track);
266     }
267 }
268