Fix the color widget's cairo arc draw calls
[led-pattern-ed] / src / led-program-dialog.vala
1 /* This file is part of LED Pattern Editor.
2  *
3  * Copyright (C) 2010 Philipp Zabel
4  *
5  * LED Pattern Editor is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * LED Pattern Editor is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with LED Pattern Editor. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 class LedProgramDialog : Gtk.Dialog {
20         private const string MCE_SERVICE = "com.nokia.mce";
21         private const string MCE_REQUEST_IF = "com.nokia.mce.request";
22         private const string MCE_REQUEST_PATH = "/com/nokia/mce/request";
23
24         private enum ResponseType {
25                 TEST = 1,
26                 COPY = 2
27         }
28
29         LedPatternView lpv;
30         LedPatternRX51 pattern;
31
32         LedColorButton led_color1;
33         LedColorButton led_color2;
34         Gtk.Widget list1;
35         Gtk.Widget list2;
36         Gtk.ToggleButton test_button;
37
38         DBus.Connection bus;
39         dynamic DBus.Object mce;
40
41         public LedProgramDialog (LedPatternRX51 _pattern) {
42                 pattern = _pattern;
43                 set_title (_("LED pattern editor - ") +
44                            (pattern.name.has_prefix ("Pattern") ?
45                             pattern.name.offset (7) : pattern.name) + _(" pattern"));
46
47                 var content = (Gtk.VBox) get_content_area ();
48                 content.set_size_request (-1, 5*70);
49
50                 lpv = new LedPatternView (pattern.copy ());
51                 lpv.set_size_request (-1, 70);
52                 content.pack_start (lpv, false, false, 0);
53
54                 var hbox = new Gtk.HBox (true, 0);
55                 list1 = led_command_list (1);
56                 hbox.pack_start (list1, true, true, 0);
57                 list2 = led_command_list (2);
58                 hbox.pack_start (list2, true, true, 0);
59                 content.pack_start (hbox, true, true, 0);
60
61                 content.show_all ();
62                 list2.hide ();
63
64                 hbox = new Gtk.HBox (true, 0);
65                 led_color1 = new LedColorButton.with_color (lpv.pattern.color1);
66                 led_color1.clicked.connect (on_color1_clicked);
67                 hbox.pack_start (led_color1, true, true, 0);
68                 led_color2 = new LedColorButton.with_color (lpv.pattern.color2);
69                 led_color2.clicked.connect (on_color2_clicked);
70                 hbox.pack_start (led_color2, true, true, 0);
71                 add_action_widget (hbox, 2);
72                 action_area.set_child_secondary (hbox, true);
73
74                 hbox = new Gtk.HBox (true, 0);
75                 var radio = (Gtk.RadioButton) Hildon.gtk_radio_button_new (Hildon.SizeType.FINGER_HEIGHT, null);
76                 radio.set_mode (false);
77                 radio.set_label ("1");
78                 radio.set_active (true);
79                 radio.toggled.connect (on_engine1_toggled);
80                 hbox.pack_start (radio, true, true, 0);
81                 radio = (Gtk.RadioButton) Hildon.gtk_radio_button_new_from_widget (Hildon.SizeType.FINGER_HEIGHT, radio);
82                 radio.set_mode (false);
83                 radio.set_label ("2");
84                 radio.toggled.connect (on_engine2_toggled);
85                 hbox.pack_start (radio, true, true, 0);
86                 add_action_widget (hbox, 2);
87                 action_area.set_child_secondary (hbox, true);
88
89                 test_button = (Gtk.ToggleButton) Hildon.gtk_toggle_button_new (Hildon.SizeType.FINGER_HEIGHT);
90                 test_button.set_label (_("Test"));
91                 add_action_widget (test_button, ResponseType.TEST);
92
93                 add_button (_("Copy"), ResponseType.COPY);
94                 add_button (_("Done"), Gtk.ResponseType.ACCEPT);
95
96                 action_area.show_all ();
97
98                 test_button.toggled.connect (on_test_toggled);
99                 key_press_event.connect (on_key_pressed);
100                 response.connect (on_response);
101
102                 bus = DBus.Bus.get (DBus.BusType.SYSTEM);
103                 mce = bus.get_object (MCE_SERVICE, MCE_REQUEST_PATH, MCE_REQUEST_IF);
104         }
105
106         private bool on_key_pressed (Gdk.EventKey event) {
107                 if (Gdk.ModifierType.CONTROL_MASK in event.state) {
108                         string key = Gdk.keyval_name (event.keyval);
109                         if (key == "c")
110                                 copy ();
111                         else if (key == "v")
112                                 paste ();
113                 }
114                 return true;
115         }
116
117         private Gtk.Widget led_command_list (int engine) {
118                 var pannable = new Hildon.PannableArea ();
119                 var vbox = new Gtk.VBox (false, 0);
120
121                 var label = new Gtk.Label (_("Engine %d:").printf (engine));
122                 label.set_alignment (0, 0.5f);
123                 vbox.pack_start (label, false, false, 0);
124
125                 unowned List<LedCommandRX51> list = (engine == 1) ?
126                                                     lpv.pattern.engine1 : lpv.pattern.engine2;
127                 foreach (LedCommandRX51 command in list) {
128                         if (command.type == CommandType.RESET_MUX)
129                                 continue;
130                         var command_widget = new LedCommandWidget (lpv.pattern, list,
131                                                                    command);
132
133                         vbox.pack_start (command_widget, false, false, 0);
134                 }
135
136                 var button = new Gtk.Button.with_label (_("New command"));
137                 Hildon.gtk_widget_set_theme_size (button, Hildon.SizeType.FINGER_HEIGHT);
138                 button.clicked.connect (on_new_command_clicked);
139                 vbox.pack_end (button, false, false, 0);
140
141                 pannable.add_with_viewport (vbox);
142                 return pannable;
143         }
144
145         void on_response (int response) {
146                 if (response == ResponseType.COPY) {
147                         copy ();
148                         return;
149                 } else if (response == Gtk.ResponseType.ACCEPT) {
150                         if (pattern.dump () != lpv.pattern.dump ()) {
151                                 pattern.replace_with (lpv.pattern);
152                         }
153                         test_button.set_active (false);
154                 } else if (response == Gtk.ResponseType.CANCEL) {
155                         test_button.set_active (false);
156                 }
157         }
158
159         void copy () {
160                 var clipboard = Gtk.Clipboard.@get (Gdk.SELECTION_CLIPBOARD);
161
162                 clipboard.set_text (lpv.pattern.dump (), -1);
163                 clipboard.store ();
164                 Hildon.Banner.show_information (null, null, _("Copied"));
165         }
166
167         void paste () {
168                 var clipboard = Gtk.Clipboard.@get (Gdk.SELECTION_CLIPBOARD);
169
170                 clipboard.request_text (on_text_received);
171         }
172
173         void on_text_received (Gtk.Clipboard clipboard, string text) {
174                 var clip_pattern = new LedPatternRX51 ();
175                 try {
176                         clip_pattern.parse (text);
177                         lpv.pattern.replace_with (clip_pattern);
178                 } catch (LedPatternError e) {
179                         Hildon.Banner.show_information (null, null, _("Not a valid pattern"));
180                 }
181         }
182
183         void on_test_toggled (Gtk.ToggleButton source) {
184                 if (source.get_active ()) {
185                         try {
186                                 mce.req_led_pattern_activate ("PatternError");
187                         } catch (DBus.Error e) {
188                                 Hildon.Banner.show_information (null, null, e.message);
189                         }
190                         Timeout.add (200, delayed_spawn);
191                 } else {
192                         try {
193                                 mce.req_led_pattern_deactivate ("PatternError");
194                         } catch (DBus.Error e) {
195                                 Hildon.Banner.show_information (null, null, e.message);
196                         }
197                 }
198         }
199
200         bool delayed_spawn () {
201                 try {
202                         int exit_status;
203                         string error;
204                         var command = "sudo /usr/bin/led-pattern-helper test \"" +
205                                       lpv.pattern.dump () + "\"";
206                         Process.spawn_command_line_sync (command, null, out error, out exit_status);
207                         if (exit_status != 0) {
208                                 var information = "Exit status: %d\n%s".printf (exit_status, error);
209                                 Hildon.Banner.show_information (null, null, information);
210                         }
211                 } catch (SpawnError e) {
212                         Hildon.Banner.show_information (null, null, e.message);
213                 }
214
215                 return false;
216         }
217
218         void on_color1_clicked (Gtk.Button button) {
219                 var dialog = new LedColorDialog ();
220                 int response = dialog.run ();
221                 if (response > 0) {
222                         LedColor color = (LedColor) response;
223                         led_color1.set_color (color);
224                         lpv.pattern.color1 = color;
225                         color = led_color2.get_color () & ~response;
226                         led_color2.set_color (color);
227                         lpv.pattern.color2 = color;
228                         lpv.pattern.changed ();
229                 }
230                 dialog.destroy ();
231         }
232
233         void on_color2_clicked (Gtk.Button button) {
234                 var dialog = new LedColorDialog ();
235                 int response = dialog.run ();
236                 if (response > 0) {
237                         LedColor color = (LedColor) response;
238                         led_color2.set_color (color);
239                         lpv.pattern.color2 = color;
240                         color = led_color1.get_color () & ~response;
241                         led_color1.set_color (color);
242                         lpv.pattern.color1 = color;
243                         lpv.pattern.changed ();
244                 }
245                 dialog.destroy ();
246         }
247
248         void on_engine1_toggled (Gtk.ToggleButton source) {
249                 if (source.get_active ())
250                         list1.show ();
251                 else
252                         list1.hide ();
253         }
254
255         void on_engine2_toggled (Gtk.ToggleButton source) {
256                 if (source.get_active ())
257                         list2.show ();
258                 else
259                         list2.hide ();
260         }
261
262         void on_new_command_clicked (Gtk.Button button) {
263                 var widget = button.parent.parent.parent;
264                 unowned List<LedCommandRX51> engine;
265                 if (widget == list1) {
266                         engine = lpv.pattern.engine1;
267                 } else if (widget == list2) {
268                         engine = lpv.pattern.engine2;
269                 } else {
270                         return;
271                 }
272
273                 var dialog = new Hildon.PickerDialog (this);
274                 dialog.set_title (_("New command"));
275
276                 var touch_selector = new Hildon.TouchSelector.text ();
277                 touch_selector.append_text (_("Set PWM"));
278                 touch_selector.append_text (_("Ramp"));
279                 touch_selector.append_text (_("Wait"));
280                 touch_selector.append_text (_("Trigger"));
281                 touch_selector.append_text (_("Go To Start"));
282                 touch_selector.append_text (_("End"));
283                 dialog.set_selector (touch_selector);
284
285                 int response = dialog.run ();
286                 if (response == Gtk.ResponseType.OK) {
287                         var command = new LedCommandRX51 ();
288                         LedCommandRX51 last_command = engine.last ().data;
289                         engine.append (command);
290                         command.changed.connect (lpv.pattern.on_changed);
291
292                         switch (touch_selector.get_active (0)) {
293                         case 0:
294                                 command.set_pwm (127);
295                                 break;
296                         case 1:
297                                 if (last_command.type == CommandType.RAMP_WAIT) {
298                                         command.ramp_wait (last_command.step_time,
299                                                            -last_command.steps);
300                                 } else if (last_command.level > 0) {
301                                         command.ramp_wait (125.0 / last_command.level,
302                                                            -last_command.level);
303                                 } else {
304                                         command.ramp_wait (0.49, 255);
305                                 }
306                                 break;
307                         case 2:
308                                 command.ramp_wait (100.0, 0);
309                                 break;
310                         case 3:
311                                 command.type = CommandType.TRIGGER;
312                                 command.code = 0xe000;
313                                 command.changed ();
314                                 break;
315                         case 4:
316                                 command.go_to_start ();
317                                 break;
318                         case 5:
319                                 command.end (false);
320                                 break;
321                         }
322                         var vbox = (Gtk.VBox) button.parent;
323                         var command_widget = new LedCommandWidget (lpv.pattern, engine,
324                                                                    command);
325                         vbox.pack_start (command_widget, false, false, 0);
326                         command_widget.show_all ();
327
328                 }
329                 dialog.destroy ();
330         }
331 }