]>
Commit | Line | Data |
---|---|---|
3f63165c UH |
1 | /* |
2 | * This file is part of the sigrok project. | |
3 | * | |
4 | * Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz> | |
5 | * | |
6 | * This program is free software: you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation, either version 3 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
20 | #include <stdlib.h> | |
21 | ||
22 | #include <sigrok.h> | |
23 | ||
24 | #include <gtk/gtk.h> | |
25 | ||
26 | #include <stdlib.h> | |
27 | ||
28 | #include "sigrok-gtk.h" | |
29 | ||
30 | enum { | |
43132a90 | 31 | DEV_PROP_HWCAP, |
3f63165c UH |
32 | DEV_PROP_TYPE, |
33 | DEV_PROP_SHORTNAME, | |
34 | DEV_PROP_DESCRIPTION, | |
35 | DEV_PROP_IS_TEXT, | |
36 | DEV_PROP_TEXTVALUE, | |
37 | DEV_PROP_BOOLVALUE, | |
38 | MAX_DEV_PROP | |
39 | }; | |
40 | ||
41 | static void prop_edited(GtkCellRendererText *cel, gchar *path, gchar *text, | |
42 | GtkListStore *props) | |
43 | { | |
44 | (void)cel; | |
45 | ||
ffe80b55 | 46 | struct sr_dev *dev = g_object_get_data(G_OBJECT(props), "dev"); |
3f63165c UH |
47 | GtkTreeIter iter; |
48 | int type, cap; | |
49 | guint64 tmp_u64; | |
50 | int ret = SR_ERR; | |
51 | ||
52 | gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(props), &iter, path); | |
53 | gtk_tree_model_get(GTK_TREE_MODEL(props), &iter, | |
43132a90 | 54 | DEV_PROP_HWCAP, &cap, |
3f63165c UH |
55 | DEV_PROP_TYPE, &type, -1); |
56 | ||
57 | switch (type) { | |
58 | case SR_T_UINT64: | |
59 | if (sr_parse_sizestring(text, &tmp_u64) != SR_OK) | |
60 | return; | |
61 | ||
97fe0e2b | 62 | ret = dev->plugin->config_set(dev->plugin_index, cap, &tmp_u64); |
3f63165c UH |
63 | break; |
64 | case SR_T_CHAR: | |
97fe0e2b | 65 | ret = dev->plugin->config_set(dev->plugin_index, cap, text); |
3f63165c UH |
66 | break; |
67 | /* SR_T_BOOL will be handled by prop_toggled */ | |
68 | } | |
69 | ||
70 | if (!ret) | |
71 | gtk_list_store_set(props, &iter, DEV_PROP_TEXTVALUE, text, -1); | |
72 | } | |
73 | ||
74 | static void prop_toggled(GtkCellRendererToggle *cel, gchar *path, | |
75 | GtkListStore *props) | |
76 | { | |
ffe80b55 | 77 | struct sr_dev *dev = g_object_get_data(G_OBJECT(props), "dev"); |
3f63165c UH |
78 | GtkTreeIter iter; |
79 | int type, cap; | |
80 | int ret; | |
81 | gboolean val; | |
82 | gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(props), &iter, path); | |
83 | gtk_tree_model_get(GTK_TREE_MODEL(props), &iter, | |
43132a90 | 84 | DEV_PROP_HWCAP, &cap, |
3f63165c UH |
85 | DEV_PROP_TYPE, &type, -1); |
86 | ||
87 | val = !gtk_cell_renderer_toggle_get_active(cel); | |
97fe0e2b UH |
88 | ret = dev->plugin->config_set(dev->plugin_index, cap, |
89 | GINT_TO_POINTER(val)); | |
3f63165c UH |
90 | |
91 | if (!ret) | |
92 | gtk_list_store_set(props, &iter, DEV_PROP_BOOLVALUE, val, -1); | |
93 | } | |
94 | ||
95 | void dev_prop_bool_data_func(GtkCellLayout *cell_layout, | |
96 | GtkCellRenderer *cell, | |
97 | GtkTreeModel *tree_model, | |
98 | GtkTreeIter *iter, | |
99 | gpointer data) | |
100 | { | |
101 | (void)cell_layout; | |
102 | (void)data; | |
103 | ||
104 | gboolean istext, val; | |
105 | gtk_tree_model_get(tree_model, iter, | |
106 | DEV_PROP_IS_TEXT, &istext, | |
107 | DEV_PROP_BOOLVALUE, &val, -1); | |
108 | g_object_set(G_OBJECT(cell), "visible", !istext, "active", val, NULL); | |
109 | } | |
110 | ||
111 | static void dev_set_options(GtkAction *action, GtkWindow *parent) | |
112 | { | |
113 | (void)action; | |
114 | ||
ffe80b55 UH |
115 | struct sr_dev *dev = g_object_get_data(G_OBJECT(parent), "dev"); |
116 | if (!dev) | |
3f63165c UH |
117 | return; |
118 | ||
119 | GtkWidget *dialog = gtk_dialog_new_with_buttons("Device Properties", | |
120 | parent, GTK_DIALOG_MODAL, | |
121 | GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, | |
122 | NULL); | |
123 | GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL); | |
124 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), | |
125 | GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
126 | gtk_widget_set_size_request(sw, 300, 200); | |
127 | GtkWidget *tv = gtk_tree_view_new(); | |
128 | gtk_container_add(GTK_CONTAINER(sw), tv); | |
129 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), sw, | |
130 | TRUE, TRUE, 0); | |
131 | ||
132 | /* Populate list store with config options */ | |
133 | GtkListStore *props = gtk_list_store_new(MAX_DEV_PROP, | |
134 | G_TYPE_INT, G_TYPE_INT, | |
135 | G_TYPE_STRING, G_TYPE_STRING, | |
136 | G_TYPE_BOOLEAN, G_TYPE_STRING, | |
137 | G_TYPE_BOOLEAN); | |
138 | gtk_tree_view_set_model(GTK_TREE_VIEW(tv), GTK_TREE_MODEL(props)); | |
43132a90 | 139 | int *hwcaps = dev->plugin->hwcap_get_all(); |
3f63165c UH |
140 | int cap; |
141 | GtkTreeIter iter; | |
43132a90 | 142 | for (cap = 0; hwcaps[cap]; cap++) { |
3f63165c | 143 | struct sr_hwcap_option *hwo; |
43132a90 | 144 | if (!(hwo = sr_hw_hwcap_get(hwcaps[cap]))) |
3f63165c UH |
145 | continue; |
146 | gtk_list_store_append(props, &iter); | |
147 | gtk_list_store_set(props, &iter, | |
43132a90 | 148 | DEV_PROP_HWCAP, hwcaps[cap], |
3f63165c UH |
149 | DEV_PROP_TYPE, hwo->type, |
150 | DEV_PROP_SHORTNAME, hwo->shortname, | |
151 | DEV_PROP_DESCRIPTION, hwo->description, | |
152 | DEV_PROP_IS_TEXT, hwo->type != SR_T_BOOL, | |
153 | -1); | |
154 | } | |
155 | ||
156 | /* Popup tooltop containing description if mouse hovers */ | |
157 | gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(tv), | |
158 | DEV_PROP_DESCRIPTION); | |
159 | ||
160 | /* Save device with list so that property can be set by edited | |
161 | * handler. */ | |
ffe80b55 | 162 | g_object_set_data(G_OBJECT(props), "dev", dev); |
3f63165c UH |
163 | |
164 | /* Add columns to the tree view */ | |
165 | GtkTreeViewColumn *col; | |
166 | col = gtk_tree_view_column_new_with_attributes("Property", | |
167 | gtk_cell_renderer_text_new(), | |
168 | "text", DEV_PROP_SHORTNAME, NULL); | |
169 | gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col); | |
170 | /* We pack both a text and toggle renderer. Only one will be visible. | |
171 | * depending on type. | |
172 | */ | |
173 | GtkCellRenderer *cel = gtk_cell_renderer_text_new(); | |
174 | g_object_set(cel, "editable", TRUE, NULL); | |
175 | g_signal_connect(cel, "edited", G_CALLBACK(prop_edited), props); | |
176 | col = gtk_tree_view_column_new_with_attributes("Value", | |
177 | cel, "text", DEV_PROP_TEXTVALUE, | |
178 | "visible", DEV_PROP_IS_TEXT, NULL); | |
179 | cel = gtk_cell_renderer_toggle_new(); | |
180 | g_signal_connect(cel, "toggled", G_CALLBACK(prop_toggled), props); | |
181 | gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(col), cel, TRUE); | |
182 | gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(col), cel, | |
183 | dev_prop_bool_data_func, NULL, NULL); | |
184 | gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col); | |
185 | ||
186 | ||
187 | gtk_widget_show_all(dialog); | |
188 | gtk_dialog_run(GTK_DIALOG(dialog)); | |
189 | ||
190 | gtk_widget_destroy(dialog); | |
191 | } | |
192 | ||
193 | enum { | |
194 | PROBE_NUMBER, | |
195 | PROBE_ENABLED, | |
196 | PROBE_NAME, | |
197 | PROBE_TRIGGER, | |
198 | MAX_PROBE | |
199 | }; | |
200 | ||
201 | static void probe_toggled(GtkCellRenderer *cel, gchar *path, | |
202 | GtkTreeModel *probes) | |
203 | { | |
ffe80b55 | 204 | struct sr_dev *dev = g_object_get_data(G_OBJECT(probes), "dev"); |
3f63165c UH |
205 | GtkTreeIter iter; |
206 | struct sr_probe *probe; | |
207 | gint i; | |
208 | gboolean en; | |
209 | ||
210 | (void)cel; | |
211 | ||
212 | gtk_tree_model_get_iter_from_string(probes, &iter, path); | |
213 | gtk_tree_model_get(probes, &iter, PROBE_NUMBER, &i, | |
214 | PROBE_ENABLED, &en, -1); | |
ffe80b55 | 215 | probe = sr_dev_probe_find(dev, i); |
3f63165c UH |
216 | probe->enabled = !en; |
217 | gtk_list_store_set(GTK_LIST_STORE(probes), &iter, | |
218 | PROBE_ENABLED, probe->enabled, -1); | |
219 | } | |
220 | ||
221 | static void probe_named(GtkCellRendererText *cel, gchar *path, gchar *text, | |
222 | GtkTreeModel *probes) | |
223 | { | |
ffe80b55 | 224 | struct sr_dev *dev = g_object_get_data(G_OBJECT(probes), "dev"); |
3f63165c UH |
225 | GtkTreeIter iter; |
226 | gint i; | |
227 | ||
228 | (void)cel; | |
229 | ||
230 | gtk_tree_model_get_iter_from_string(probes, &iter, path); | |
231 | gtk_tree_model_get(probes, &iter, PROBE_NUMBER, &i, -1); | |
ffe80b55 | 232 | sr_dev_probe_name(dev, i, text); |
3f63165c UH |
233 | gtk_list_store_set(GTK_LIST_STORE(probes), &iter, PROBE_NAME, text, -1); |
234 | } | |
235 | ||
236 | static void probe_trigger_set(GtkCellRendererText *cel, gchar *path, | |
237 | gchar *text, GtkTreeModel *probes) | |
238 | { | |
ffe80b55 | 239 | struct sr_dev *dev = g_object_get_data(G_OBJECT(probes), "dev"); |
3f63165c UH |
240 | GtkTreeIter iter; |
241 | gint i; | |
242 | ||
243 | (void)cel; | |
244 | ||
245 | gtk_tree_model_get_iter_from_string(probes, &iter, path); | |
246 | gtk_tree_model_get(probes, &iter, PROBE_NUMBER, &i, -1); | |
ffe80b55 | 247 | sr_dev_trigger_set(dev, i, text); |
3f63165c UH |
248 | gtk_list_store_set(GTK_LIST_STORE(probes), &iter, |
249 | PROBE_TRIGGER, text, -1); | |
250 | } | |
251 | ||
252 | static void dev_set_probes(GtkAction *action, GtkWindow *parent) | |
253 | { | |
254 | (void)action; | |
255 | ||
ffe80b55 UH |
256 | struct sr_dev *dev = g_object_get_data(G_OBJECT(parent), "dev"); |
257 | if (!dev) | |
3f63165c UH |
258 | return; |
259 | ||
260 | GtkWidget *dialog = gtk_dialog_new_with_buttons("Configure Probes", | |
261 | parent, GTK_DIALOG_MODAL, | |
262 | GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, | |
263 | NULL); | |
264 | GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL); | |
265 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), | |
266 | GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
267 | gtk_widget_set_size_request(sw, 300, 200); | |
268 | GtkWidget *tv = gtk_tree_view_new(); | |
269 | gtk_container_add(GTK_CONTAINER(sw), tv); | |
270 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), sw, | |
271 | TRUE, TRUE, 0); | |
272 | ||
273 | /* Populate list store with probe options */ | |
274 | GtkListStore *probes = gtk_list_store_new(MAX_PROBE, | |
275 | G_TYPE_INT, G_TYPE_BOOLEAN, | |
276 | G_TYPE_STRING, GTK_TYPE_STRING); | |
277 | gtk_tree_view_set_model(GTK_TREE_VIEW(tv), GTK_TREE_MODEL(probes)); | |
278 | GtkTreeIter iter; | |
279 | GSList *p; | |
280 | int i; | |
ffe80b55 | 281 | for (p = dev->probes, i = 1; p; p = g_slist_next(p), i++) { |
3f63165c UH |
282 | struct sr_probe *probe = p->data; |
283 | gtk_list_store_append(probes, &iter); | |
284 | gtk_list_store_set(probes, &iter, PROBE_NUMBER, i, | |
285 | PROBE_ENABLED, probe->enabled, | |
286 | PROBE_NAME, probe->name, | |
287 | PROBE_TRIGGER, probe->trigger, | |
288 | -1); | |
289 | } | |
290 | ||
291 | /* Save device with list so that property can be set by edited | |
292 | * handler. */ | |
ffe80b55 | 293 | g_object_set_data(G_OBJECT(probes), "dev", dev); |
3f63165c UH |
294 | |
295 | /* Add columns to the tree view */ | |
296 | GtkTreeViewColumn *col; | |
297 | col = gtk_tree_view_column_new_with_attributes("Probe", | |
298 | gtk_cell_renderer_text_new(), | |
299 | "text", PROBE_NUMBER, NULL); | |
300 | gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col); | |
301 | GtkCellRenderer *cel = gtk_cell_renderer_toggle_new(); | |
302 | g_object_set(cel, "activatable", TRUE, NULL); | |
303 | g_signal_connect(cel, "toggled", G_CALLBACK(probe_toggled), probes); | |
304 | col = gtk_tree_view_column_new_with_attributes("En", | |
305 | cel, "active", PROBE_ENABLED, NULL); | |
306 | gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col); | |
307 | cel = gtk_cell_renderer_text_new(); | |
308 | g_object_set(cel, "editable", TRUE, NULL); | |
309 | g_signal_connect(cel, "edited", G_CALLBACK(probe_named), probes); | |
310 | col = gtk_tree_view_column_new_with_attributes("Signal Name", cel, | |
311 | "text", PROBE_NAME, | |
312 | "sensitive", PROBE_ENABLED, NULL); | |
313 | gtk_tree_view_column_set_resizable(col, TRUE); | |
314 | gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col); | |
315 | cel = gtk_cell_renderer_text_new(); | |
316 | g_object_set(cel, "editable", TRUE, NULL); | |
317 | g_signal_connect(cel, "edited", G_CALLBACK(probe_trigger_set), probes); | |
318 | col = gtk_tree_view_column_new_with_attributes("Trigger", cel, | |
319 | "text", PROBE_TRIGGER, | |
320 | "sensitive", PROBE_ENABLED, NULL); | |
321 | gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col); | |
322 | ||
323 | gtk_widget_show_all(dialog); | |
324 | gtk_dialog_run(GTK_DIALOG(dialog)); | |
325 | ||
326 | gtk_widget_destroy(dialog); | |
327 | } | |
328 | ||
329 | static void capture_run(GtkAction *action, GObject *parent) | |
330 | { | |
331 | (void)action; | |
332 | ||
ffe80b55 | 333 | struct sr_dev *dev = g_object_get_data(G_OBJECT(parent), "dev"); |
3f63165c UH |
334 | GtkEntry *timesamples = g_object_get_data(parent, "timesamples"); |
335 | GtkComboBox *timeunit = g_object_get_data(parent, "timeunit"); | |
336 | gint i = gtk_combo_box_get_active(timeunit); | |
337 | guint64 time_msec = 0; | |
338 | guint64 limit_samples = 0; | |
339 | ||
340 | switch (i) { | |
341 | case 0: /* Samples */ | |
342 | sr_parse_sizestring(gtk_entry_get_text(timesamples), | |
343 | &limit_samples); | |
344 | break; | |
345 | case 1: /* Milliseconds */ | |
346 | time_msec = strtoull(gtk_entry_get_text(timesamples), NULL, 10); | |
347 | break; | |
348 | case 2: /* Seconds */ | |
349 | time_msec = strtoull(gtk_entry_get_text(timesamples), NULL, 10) | |
350 | * 1000; | |
351 | break; | |
352 | } | |
353 | ||
354 | if (time_msec) { | |
ffe80b55 | 355 | if (sr_hw_has_hwcap(dev->plugin, SR_HWCAP_LIMIT_MSEC)) { |
97fe0e2b UH |
356 | if (dev->plugin->config_set(dev->plugin_index, |
357 | SR_HWCAP_LIMIT_MSEC, | |
358 | &time_msec) != SR_OK) { | |
3f63165c UH |
359 | g_critical("Failed to configure time limit."); |
360 | sr_session_destroy(); | |
361 | return; | |
362 | } | |
363 | } else { | |
364 | /* time limit set, but device doesn't support this... | |
365 | * convert to samples based on the samplerate. | |
366 | */ | |
367 | limit_samples = 0; | |
ffe80b55 | 368 | if (sr_dev_has_hwcap(dev, SR_HWCAP_SAMPLERATE)) { |
3f63165c | 369 | guint64 tmp_u64; |
664bab64 | 370 | tmp_u64 = *((uint64_t *)dev->plugin->dev_info_get( |
ffe80b55 | 371 | dev->plugin_index, |
3f63165c UH |
372 | SR_DI_CUR_SAMPLERATE)); |
373 | limit_samples = tmp_u64 * time_msec / (uint64_t) 1000; | |
374 | } | |
375 | if (limit_samples == 0) { | |
376 | g_critical("Not enough time at this samplerate."); | |
377 | return; | |
378 | } | |
379 | ||
97fe0e2b UH |
380 | if (dev->plugin->config_set(dev->plugin_index, |
381 | SR_HWCAP_LIMIT_SAMPLES, | |
382 | &limit_samples) != SR_OK) { | |
3f63165c UH |
383 | g_critical("Failed to configure time-based sample limit."); |
384 | return; | |
385 | } | |
386 | } | |
387 | } | |
388 | if (limit_samples) { | |
97fe0e2b UH |
389 | if (dev->plugin->config_set(dev->plugin_index, |
390 | SR_HWCAP_LIMIT_SAMPLES, | |
391 | &limit_samples) != SR_OK) { | |
3f63165c UH |
392 | g_critical("Failed to configure sample limit."); |
393 | return; | |
394 | } | |
395 | } | |
396 | ||
97fe0e2b UH |
397 | if (dev->plugin->config_set(dev->plugin_index, |
398 | SR_HWCAP_PROBECONFIG, (char *)dev->probes) != SR_OK) { | |
3f63165c UH |
399 | printf("Failed to configure probes.\n"); |
400 | sr_session_destroy(); | |
401 | return; | |
402 | } | |
403 | ||
404 | if (sr_session_start() != SR_OK) { | |
405 | g_critical("Failed to start session."); | |
406 | return; | |
407 | } | |
408 | ||
409 | sr_session_run(); | |
410 | } | |
411 | ||
412 | static void dev_file_open(GtkAction *action, GtkWindow *parent) | |
413 | { | |
414 | (void)action; | |
415 | static GtkWidget *dialog; | |
416 | const gchar *filename; | |
417 | ||
418 | if(!dialog) | |
419 | dialog = gtk_file_chooser_dialog_new("Open", parent, | |
420 | GTK_FILE_CHOOSER_ACTION_OPEN, | |
421 | GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | |
422 | GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); | |
423 | g_signal_connect(dialog, "delete-event", | |
424 | G_CALLBACK(gtk_widget_hide_on_delete), | |
425 | NULL); | |
426 | ||
427 | if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) { | |
428 | /* Dialog was cancelled or closed */ | |
429 | gtk_widget_hide(dialog); | |
430 | return; | |
431 | } | |
432 | ||
433 | gtk_widget_hide(dialog); | |
434 | ||
435 | filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); | |
436 | load_input_file(parent, filename); | |
437 | } | |
438 | ||
439 | void toggle_log(GtkToggleAction *action, GObject *parent) | |
440 | { | |
441 | GtkWidget *log = g_object_get_data(parent, "logview"); | |
442 | gtk_widget_set_visible(log, gtk_toggle_action_get_active(action)); | |
443 | } | |
444 | ||
445 | void zoom_in(GtkAction *action, GObject *parent) | |
446 | { | |
447 | (void)action; | |
448 | ||
449 | GtkWidget *sigview = g_object_get_data(parent, "sigview"); | |
450 | sigview_zoom(sigview, 1.5, 0); | |
451 | } | |
452 | ||
453 | void zoom_out(GtkAction *action, GObject *parent) | |
454 | { | |
455 | (void)action; | |
456 | ||
457 | GtkWidget *sigview = g_object_get_data(parent, "sigview"); | |
458 | sigview_zoom(sigview, 1/1.5, 0); | |
459 | } | |
460 | ||
461 | void zoom_fit(GtkAction *action, GObject *parent) | |
462 | { | |
463 | (void)action; | |
464 | ||
465 | GtkWidget *sigview = g_object_get_data(parent, "sigview"); | |
466 | sigview_zoom(sigview, 0, 0); | |
467 | } | |
468 | ||
469 | static const GtkActionEntry action_items[] = { | |
470 | /* name, stock-id, label, accel, tooltip, callback */ | |
471 | {"DevMenu", NULL, "_Device", NULL, NULL, NULL}, | |
472 | {"DevOpen", GTK_STOCK_OPEN, "_Open", "<control>O", | |
473 | "Open Session File", G_CALLBACK(dev_file_open)}, | |
474 | {"DevSelectMenu", NULL, "Select Device", NULL, NULL, NULL}, | |
475 | {"DevRescan", GTK_STOCK_REFRESH, "_Rescan", "<control>R", | |
476 | "Rescan for LA devices", G_CALLBACK(dev_select_rescan)}, | |
477 | {"DevProperties", GTK_STOCK_PROPERTIES, "_Properties", "<control>P", | |
478 | "Configure LA", G_CALLBACK(dev_set_options)}, | |
479 | {"DevProbes", GTK_STOCK_COLOR_PICKER, "_Probes", "<control>O", | |
480 | "Configure Probes", G_CALLBACK(dev_set_probes)}, | |
481 | {"DevAcquire", GTK_STOCK_EXECUTE, "_Acquire", "<control>A", | |
482 | "Acquire Samples", G_CALLBACK(capture_run)}, | |
483 | {"Exit", GTK_STOCK_QUIT, "E_xit", "<control>Q", | |
484 | "Exit the program", G_CALLBACK(gtk_main_quit) }, | |
485 | ||
486 | {"ViewMenu", NULL, "_View", NULL, NULL, NULL}, | |
487 | {"ViewZoomIn", GTK_STOCK_ZOOM_IN, "Zoom _In", "<control>z", NULL, | |
488 | G_CALLBACK(zoom_in)}, | |
489 | {"ViewZoomOut", GTK_STOCK_ZOOM_OUT, "Zoom _Out", "<control><shift>Z", | |
490 | NULL, G_CALLBACK(zoom_out)}, | |
491 | {"ViewZoomFit", GTK_STOCK_ZOOM_FIT, NULL, NULL, | |
492 | NULL, G_CALLBACK(zoom_fit)}, | |
493 | ||
494 | {"HelpMenu", NULL, "_Help", NULL, NULL, NULL}, | |
495 | {"HelpWiki", GTK_STOCK_ABOUT, "Sigrok _Wiki", NULL, NULL, | |
496 | G_CALLBACK(help_wiki)}, | |
497 | {"HelpAbout", GTK_STOCK_ABOUT, "_About", NULL, NULL, | |
498 | G_CALLBACK(help_about)}, | |
499 | }; | |
500 | ||
501 | static const GtkToggleActionEntry toggle_items[] = { | |
502 | /* name, stock-id, label, accel, tooltip, callback, isactive */ | |
503 | {"ViewLog", GTK_STOCK_JUSTIFY_LEFT, "_Log", NULL, NULL, | |
504 | G_CALLBACK(toggle_log), FALSE}, | |
505 | }; | |
506 | ||
507 | static const char ui_xml[] = | |
508 | "<ui>" | |
509 | " <menubar>" | |
510 | " <menu action='DevMenu'>" | |
511 | " <menuitem action='DevOpen'/>" | |
512 | " <separator/>" | |
513 | " <menu action='DevSelectMenu'>" | |
514 | " <separator/>" | |
515 | " <menuitem action='DevRescan'/>" | |
516 | " </menu>" | |
517 | " <menuitem action='DevProperties'/>" | |
518 | " <menuitem action='DevProbes'/>" | |
519 | " <separator/>" | |
520 | " <menuitem action='DevAcquire'/>" | |
521 | " <separator/>" | |
522 | " <menuitem action='Exit'/>" | |
523 | " </menu>" | |
524 | " <menu action='ViewMenu'>" | |
525 | " <menuitem action='ViewZoomIn'/>" | |
526 | " <menuitem action='ViewZoomOut'/>" | |
527 | " <menuitem action='ViewZoomFit'/>" | |
528 | " <separator/>" | |
529 | " <menuitem action='ViewLog'/>" | |
530 | " </menu>" | |
531 | " <menu action='HelpMenu'>" | |
532 | " <menuitem action='HelpWiki'/>" | |
533 | " <menuitem action='HelpAbout'/>" | |
534 | " </menu>" | |
535 | " </menubar>" | |
536 | " <toolbar>" | |
537 | " <placeholder name='DevSelect'/>" | |
538 | " <toolitem action='DevRescan'/>" | |
539 | " <toolitem action='DevProperties'/>" | |
540 | " <toolitem action='DevProbes'/>" | |
541 | " <separator/>" | |
542 | " <placeholder name='DevSampleCount' />" | |
543 | " <toolitem action='DevAcquire'/>" | |
544 | " <separator/>" | |
545 | " <toolitem action='ViewZoomIn'/>" | |
546 | " <toolitem action='ViewZoomOut'/>" | |
547 | " <toolitem action='ViewZoomFit'/>" | |
548 | " <separator/>" | |
549 | " </toolbar>" | |
550 | "</ui>"; | |
551 | ||
552 | GtkWidget *toolbar_init(GtkWindow *parent) | |
553 | { | |
554 | GtkWidget *vbox = gtk_vbox_new(FALSE, 0); | |
555 | GtkToolbar *toolbar; | |
556 | GtkActionGroup *ag = gtk_action_group_new("Actions"); | |
557 | gtk_action_group_add_actions(ag, action_items, | |
558 | G_N_ELEMENTS(action_items), parent); | |
559 | gtk_action_group_add_toggle_actions(ag, toggle_items, | |
560 | G_N_ELEMENTS(toggle_items), parent); | |
561 | ||
562 | GtkUIManager *ui = gtk_ui_manager_new(); | |
563 | g_object_set_data(G_OBJECT(parent), "ui_manager", ui); | |
564 | gtk_ui_manager_insert_action_group(ui, ag, 0); | |
565 | GtkAccelGroup *accel = gtk_ui_manager_get_accel_group(ui); | |
566 | gtk_window_add_accel_group(parent, accel); | |
567 | ||
568 | GError *error = NULL; | |
569 | if (!gtk_ui_manager_add_ui_from_string (ui, ui_xml, -1, &error)) { | |
570 | g_message ("building menus failed: %s", error->message); | |
571 | g_error_free (error); | |
572 | exit (-1); | |
573 | } | |
574 | ||
575 | GtkWidget *menubar = gtk_ui_manager_get_widget(ui, "/menubar"); | |
576 | gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(menubar), FALSE, TRUE, 0); | |
577 | toolbar = GTK_TOOLBAR(gtk_ui_manager_get_widget(ui, "/toolbar")); | |
578 | gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(toolbar), FALSE, TRUE, 0); | |
579 | ||
580 | /* Device selection GtkComboBox */ | |
581 | GtkToolItem *toolitem = gtk_tool_item_new(); | |
582 | GtkWidget *align = gtk_alignment_new(0.5, 0.5, 2, 0); | |
583 | GtkWidget *dev = dev_select_combo_box_new(parent); | |
584 | ||
585 | gtk_container_add(GTK_CONTAINER(align), dev); | |
586 | gtk_container_add(GTK_CONTAINER(toolitem), align); | |
587 | gtk_toolbar_insert(toolbar, toolitem, 0); | |
588 | ||
589 | /* Time/Samples entry */ | |
590 | toolitem = gtk_tool_item_new(); | |
591 | GtkWidget *timesamples = gtk_entry_new(); | |
592 | gtk_entry_set_text(GTK_ENTRY(timesamples), "100"); | |
593 | gtk_entry_set_alignment(GTK_ENTRY(timesamples), 1.0); | |
594 | gtk_widget_set_size_request(timesamples, 100, -1); | |
595 | gtk_container_add(GTK_CONTAINER(toolitem), timesamples); | |
596 | gtk_toolbar_insert(toolbar, toolitem, 7); | |
597 | ||
598 | /* Time unit combo box */ | |
599 | toolitem = gtk_tool_item_new(); | |
600 | align = gtk_alignment_new(0.5, 0.5, 2, 0); | |
601 | GtkWidget *timeunit = gtk_combo_box_new_text(); | |
602 | gtk_combo_box_append_text(GTK_COMBO_BOX(timeunit), "samples"); | |
603 | gtk_combo_box_append_text(GTK_COMBO_BOX(timeunit), "ms"); | |
604 | gtk_combo_box_append_text(GTK_COMBO_BOX(timeunit), "s"); | |
605 | gtk_combo_box_set_active(GTK_COMBO_BOX(timeunit), 0); | |
606 | gtk_container_add(GTK_CONTAINER(align), timeunit); | |
607 | gtk_container_add(GTK_CONTAINER(toolitem), align); | |
608 | gtk_toolbar_insert(toolbar, toolitem, 8); | |
609 | ||
610 | g_object_set_data(G_OBJECT(parent), "timesamples", timesamples); | |
611 | g_object_set_data(G_OBJECT(parent), "timeunit", timeunit); | |
612 | ||
613 | return GTK_WIDGET(vbox); | |
614 | } | |
615 |